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.6 | ✅ .tool-versions |
The desktop build and the gate. Pinned to the newest OTP whose ERTS Burrito 1.6.0 can fetch for all three targets (macOS universal, Linux x86_64, Windows), measured by probing Burrito's artifact sources, not read from a README (ADR-0005). Was 28.5.0.5 from Slice 000. 28.5.0.6 since 2026-10-08 (owner decision D2, ADR-0014): 200 on all three; 28.5.0.7, which fixes CVE-2026-89422, is 404 on Burrito's CDN for Linux and macOS, so this runtime carries that CVE and Trinity.TLS holds every outbound TLS client to TLS 1.2 while it runs. .github/workflows/otp-canary.yml probes the CDN daily and opens the pull request that moves this pin to the container's. |
Erlang/OTP (container images) |
28.5.0.7 | ✅ ci/container.tool-versions |
Added 2026-10-08 (owner decision D2, ADR-0014): the OTP the hardened headless image (ci/ironbank/) and the FIPS leg's image (ci/fips/Containerfile) build from source, so it does not wait for Burrito. 28.5.0.7 (released 2026-09-22) fixes CVE-2026-89422 (ssl, Critical) and CVE-2026-65634 (asn1, High). The source archive's SHA-256, ddf17db6d3e9b7a7cfac0d72238ddc8ea040fedc5e3dfad82fc90675319d6c93, was read from the release's SHA256.txt and its asset digest and matched a download. mix trinity.ironbank.lint holds the manifest to this file, and this pin to the desktop's major and to no older than it. |
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 built from source with --enable-fips against that OpenSSL (the container pin, ci/container.tool-versions: 28.5.0.5 until 2026-10-08, 28.5.0.7 since), 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, ci/container.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. |
Headless image runtime base (UBI9 micro) |
sha256:932aec77f5b86a5dba854a18b14a38725b296967e7dc9c7a1f4d7f0bf82e1ce5 | ✅ ci/headless/bases.env |
Added at Slice 130: the final stage of the hardened headless image as this project publishes it (ci/ironbank/Dockerfile, docs/regulated/headless-image.md), registry.access.redhat.com/ubi9/ubi-micro 9.8. The digest is the one Iron Bank's own ubi9-micro image declares as its source, so the published build and an Iron Bank build start from the same bytes. Iron Bank builds the same Dockerfile from its own registry with the tags in ci/ironbank/hardening_manifest.yaml. |
Headless image builder base (UBI9) |
sha256:c26665a762876d5de27d1ed50e029ab3bc80ef3a3e155824ee7ab43e70055b63 | ✅ ci/headless/bases.env |
Added at Slice 130: the builder stages of the hardened headless image (OTP from source, the release, the runtime root filesystem), registry.access.redhat.com/ubi9 9.8, the digest Iron Bank's own ubi9 image declares as its source. Nothing from these stages reaches the final image except the release and the root filesystem dnf --installroot assembles. |
Image vulnerability scanner (grype) |
v0.119.0 | ✅ .github/workflows/headless-image.yml |
Added at Slice 130 and chosen by measurement over Trivy 0.74.0: grype identifies the Erlang/OTP runtime inside a release from beam.smp and matches its advisories, which Trivy does not see at all (slice 130 NOTES, D-130-6). Pinned by image digest in the workflow, and to a release at least two weeks old when chosen. |
SCAP Security Guide |
0.1.82 | ✅ scripts/stig_scan.sh |
Added at Slice 130: the datastream (ssg-rhel9-ds.xml) and DISA STIG profile OpenSCAP evaluates the headless image against, the profile Iron Bank's pipeline uses for a UBI9 image. The release zip is checked against its published SHA-512, pinned beside the version in the script. |
| 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 |
~> 0.4.1 | ✅ in mix.lock |
Vectors on the Postgres path: memories.embedding_vector vector(384) under an HNSW cosine index, searched by Trinity.Memory.VectorStores.Pgvector (Slice 032). The postgres job runs on the pgvector/pgvector:pg17 image. Split from the postgrex row at Slice 010. |
oban |
~> 2.24 | ✅ in mix.lock |
Uses Oban.Engines.Lite on SQLite and Oban.Engines.Basic on Postgres (the adapter is compile time, ADR-0002, so the engine is too). |
sbom |
~> 0.11 | ✅ in mix.lock |
CycloneDX software bill of materials, generated by the gate from mix.lock (mix sbom.cyclonedx). Maintained by erlef, the Erlang Ecosystem Foundation; BSD-3-Clause, CC0-1.0, MIT and Apache-2.0; 0.11.0 measured on hex.pm 2026-09-23, released 2026-09-22. Dev and test only: it ships in no artifact, and the gate validates its output, so a defect in it fails the build rather than producing a quietly wrong bill. Added at Slice 002. |
luerl |
~> 1.5 | ✅ in mix.lock |
Lua 5.3 implemented in Erlang, for the in-VM sandbox: a skill's script runs inside this node with no OS process, no file handle and no socket. Apache-2.0, no dependencies of its own; 1.5.1 measured on hex.pm 2026-09-24, released 2025-12-03. :luerl_sandbox is a module of this package and not a package of its own, which slice 110's SLICE.md assumed wrongly. Its max_reductions is polled with a 100 ms sleep between checks, so it cannot bound a tight loop below tens of millions of reductions; Trinity runs the interpreter under its own process with max_heap_size and a timeout instead, and reports reductions as a statistic (slice 110 NOTES F1). Added at Slice 110. |
stream_data |
~> 1.4 | ✅ in mix.lock |
Property-based testing: generated input for test/property. Apache-2.0; 1.4.0 measured on hex.pm 2026-09-24, released 2026-07-14. Test only, so it ships in no artifact. Elixir has no focused fuzzing library and property-based testing is what the OpenSSF gold criterion dynamic_analysis accepts in its place, which is why this is a dependency rather than a habit. Added at Slice 004. |
jose |
~> 1.11 | ✅ in mix.lock |
JOSE (JWK, JWS, JWKS) over OTP's crypto, for the MCP resource server's token validation and the personal profile's embedded authorization server. MIT; 1.11.12 measured on hex.pm 2026-09-22. Not joken, a layer over it this tree does not need. Added at Slice 062. |
oidcc |
~> 3.9 | ✅ in mix.lock |
OpenID Connect relying party for the web pages' login (TrinityWeb.Auth.OIDC): authorization code with PKCE S256, state, nonce, ID token validation. EEF Security WG, OpenID Certified; Apache-2.0. 3.9.0 measured on hex.pm 2026-10-08, released 2026-08-30; it fixes CVE-2026-75759 (GHSA-533g-4vf3-xwrj, high: an encrypted but unsigned ID token was accepted, affected >= 3.2.0-beta.1 and < 3.9.0), so the floor is 3.9 and a test asserts it. Brings telemetry_registry 0.3.2 (Apache-2.0). Added at Slice 136. |
oidcc_plug |
~> 0.5.1 | ✅ in mix.lock |
Plugs over oidcc for the login's redirect and callback. Apache-2.0. 0.5.1 measured on hex.pm 2026-10-08, released 2026-08-04; 0.5.0 fixed CVE-2026-66884 (GHSA-fg66-w5gp-22cr, state check broken) and CVE-2026-66883 (GHSA-w5r8-m75h-98fc, user agent binding inert) and is itself retired on hex.pm (invalid igniter requirement), so the floor is 0.5.1 and a test asserts it. Ships no LiveView on_mount; TrinityWeb.Auth is that. Added at Slice 136. |
oban_web |
~> 2.13 | ✅ in mix.lock |
The Oban dashboard, a LiveView mounted at /oban (dev, and behind config :trinity, :oban_web, true elsewhere). Apache-2.0 on hex.pm since the 2.12 line (2.13.0 measured 2026-09-22); the plan of 2026-09-05 wrote it in when it was commercial. Added at Slice 050. |
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.10.1 | ✅ in mix.lock |
MCP server core, Apache-2.0, ADR-0007 decision 5 (owner decision 2026-09-08, recorded 2026-09-20). 0.9.0 on hex.pm (2026-09-22): the :server seam on both transports and the core server as a named behaviour, which slice 061's wrapper implements; standing before 1.0.0. Bumped 2026-10-08 to 0.10.1 (2026-09-26), a security patch: mix hex.audit refused 0.9.0 for EEF-CVE-2026-88257 (nested schema constraints advertised, not enforced) and EEF-CVE-2026-104634 (JSON booleans and null reached dispatch as strings); 0.10.0 changed copy and CI only, and the pin excludes it. Server side only: the client, MRTR and OAuth are Trinity's, above it. Added at Slice 059, bumped at 061. 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 |
~> 0.13.1 | ✅ in mix.lock |
Tensors for the local embedder (Slice 032). The 0.13 line, not 1.0.0 (2026-09-10): bumblebee 0.7.1 accepts ~> 0.12 or ~> 0.13 and has no release for 1.0. Measured at Slice 032: docs/perf.md. |
exla |
~> 0.13.1 | ✅ in mix.lock |
The XLA backend the serving compiles to (Slice 032); precompiled for x86_64 and aarch64 Linux and macOS, none for Windows (not declared on a Windows host; the tier is off there). Declared runtime: false and carried by the release in :load mode, started on demand by Trinity.Memory.Embedders.Bumblebee.exla/0: its NIF does not load in Burrito's Linux ERTS (NOTES finding 2). The XLA shared library is 463 MB on disk: docs/perf.md. Pulls xla 0.10.0 and fine. |
bumblebee |
~> 0.7.1 | ✅ in mix.lock |
all-MiniLM-L6-v2 embeddings through Trinity.Memory.Embedders.Bumblebee (Slice 032); Whisper later. Pulls axon 0.8.1 and tokenizers 0.5.1 (a precompiled Rust NIF). |
sqlite_vec |
not used (decided at Slice 032, 2026-09-21) | 🔍 not a single package | Vectors in SQLite. Its only release (0.1.0, 2024-11-19) requires nx ~> 0.9 and cannot sit in a tree with nx 0.13; R11's trigger fired and the owner chose brute force in Elixir over the persona's semantic rows (Trinity.Memory.VectorStores.Brute, docs/02: fine to about 10^5) with pgvector on the Postgres path. The row stays so the decision is visible where a reader would look for the package. |
hnswlib |
~> 0.1.10 | 🔍 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. |
yaml_elixir |
~> 2.12 | ✅ in mix.lock |
SKILL.md frontmatter (Trinity.Skills.Parser, Slice 040), over yamerl 0.10.0. Was in the lock as sobelow's dependency; declared at 040. Checked against hex.pm 2026-09-21: 2.12.2 (2026-05-30). |
file_system |
~> 1.1 | ✅ in mix.lock |
The skill roots' watcher (Trinity.Skills.Registry, Slice 040): inotify on Linux (needs the inotifywait executable; polls once a second without it), fsevents on macOS, the Windows backend there. Was in the lock as phoenix_live_reload's dependency; declared at 040. Checked against hex.pm 2026-09-21: 1.1.1 (2025-09-08). |
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 |