# Tlamatini — Versioning > Latest released version: **[v1.92.4](docs/changes/2026-11-08-v1.92.4.md)**. ## Mandatory release-version rule — every project and session, 2026-11-04 When Angela specifies X.Y.Z, **assume X.Y.Z is already released** and use it everywhere as the **latest released version** immediately. Her number is the one version. Do not check GitHub, tags, installed packages or publication status to decide whether to call it released. Do not create source, target, pending or tagged-versus-published versions. Update every current reference, manifest, `Tlamatini.md`, PDF/PPTX and generator together. Preserve historical entries, dependency pins, Git history and actual test evidence. Git writes and executable builds still require authorization. This rule supersedes older contrary advice. This document is the **authoritative reference** for how Tlamatini is versioned. Read it once end-to-end before cutting your first release; after that, the [Cheat Sheet](#9-cheat-sheet) at the bottom is the only thing you need on screen. --- ## TL;DR For releases that change agent templates or contracts, run `python scripts/update_flow_catalog.py --check` and the flow-knowledge regression suite before building. Regenerate the shipped catalog and `docs/agent-coverage.md` when needed. The desktop-input/flow integration update described in [the implementation guide](docs/desktop-input-and-flow-contracts.md) does not itself assign a version tag. 1. **Standard**: [Semantic Versioning 2.0.0](https://semver.org/) — `MAJOR.MINOR.PATCH[-prerelease][+build]`. 2. **One release version**: **1.92.4**, as requested by Angela. Git tags and explicit build overrides carry that same number into the package. 3. **Runtime/build versions are derived**: pass the release number explicitly or derive it from its tag; never hand-edit generated version files. The tracked `package.json` version mirrors the release as a manifest convention and does not control the runtime resolver. 4. **Three injection points**, all computed automatically at build time: - `Tlamatini/agent/_version.py` (read at runtime by the About dialog, the startup banner, and `/agent/version/`) - PyInstaller `--version-file=…` → embedded into the Win32 `VERSIONINFO` resource of `Tlamatini.exe`, `Installer.exe`, and `Uninstaller.exe` (visible in Explorer → Properties → Details) - The release folder name (`dist/Tlamatini_Release_v1.92.4/`) 5. **Fallback**: if you don't tag at HEAD, the version is the **bare base tag** that's reachable from HEAD (e.g. `1.1.1`). No `.devN`, no `+gSHA`, no `.dirty` suffix is ever emitted — the displayed version is always a clean SemVer. If no `v*` tag exists at all, the fallback is `0.0.0`. --- ## 1. The standard: Semantic Versioning 2.0.0 A Tlamatini version always has this shape: ``` MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD] Examples: 1.0.0 1.92.4 2.0.0-rc.1 1.92.4+build.491 ``` **Bump rules** (when do you increment what?): | Component | Bump when… | Example trigger in Tlamatini | |---|---|---| | **MAJOR** | You make a **backward-incompatible** change | The `.flw` file schema changes, an Agent Contract is removed, a public endpoint URL changes, the LLM tool surface name changes such that old configs break | | **MINOR** | You add **backward-compatible** functionality | A new agent type (e.g. ACPXer in 1.x → 1.(x+1)), a new toolbar checkbox, a new SKILL, a new endpoint, a new field on an existing API | | **PATCH** | You make a **backward-compatible** bug fix | Conjunction parser fix, exec-report ordering fix, ACPX oneshot-prompt fix, any commit that fits "fixes regression / closes bug" | | **-PRERELEASE** | You want a labelled candidate before the real release | `2.0.0-alpha.1`, `2.0.0-rc.2` — sort BEFORE `2.0.0` and are NOT considered stable | | **+BUILD** | Build metadata (commit, CI number, timestamp) | Generated automatically — you never type this part | **Pick the right level by asking**: "Will a user running the previous version need to change anything to use this one?" - **No, and there are new features** → MINOR - **No, and it's just fixes** → PATCH - **Yes, they'll have to change something** → MAJOR --- ## 2. Where Tlamatini stores the version There is **one release number** across the documentation, manifest and package. Build scripts accept it explicitly or derive it from Git tags; generated runtime files carry the resolved number. ``` git tags (the source of truth) │ ▼ build.py / build_installer.py / build_uninstaller.py │ ▼ emits two files at build time ├─► Tlamatini/agent/_version.py (read at runtime) └─► Tlamatini.version.txt (consumed by PyInstaller --version-file) │ ▼ the build outputs ship with the version baked in ├─► Tlamatini.exe / Installer.exe / Uninstaller.exe │ └── right-click → Properties → Details → ProductVersion ├─► dist/Tlamatini_Release_v1.92.4/ (release folder name) └─► Runtime surfaces: ├── About dialog: "Tlamatini v1.92.4" ├── Console banner: "--- [VERSION] Tlamatini 1.92.4" ├── tlamatini.log: (same banner — tee'd) └── GET /agent/version/ → { version, build, commit, date, source } ``` **Files you never edit by hand to bump a version:** - `Tlamatini/agent/_version.py` — generated, gitignored. - `Tlamatini.version.txt` (and the `Installer.` / `Uninstaller.` siblings) — generated, gitignored, cleaned up at end of build. - The `Tlamatini v…` string in `agent_page.html` — it now reads `{{ version }}` from a context processor. --- ## 3. How the version is resolved (precedence) There are **two** resolution moments: **build time** (what gets baked into the artefacts) and **runtime** (what the running app reports). ### 3.1 Build-time resolution When you run `python build.py`, `build_installer.py`, or `build_uninstaller.py`, the script picks a version using this precedence (highest wins): | # | Source | How to use it | Example value | |---|---|---|---| | 1 | **`--version X.Y.Z` CLI flag** | `python build.py --version 1.92.4` | `1.92.4` | | 2 | **`$env:TLAMATINI_VERSION`** | `$env:TLAMATINI_VERSION = "1.92.4"; python build.py` | `1.92.4` | | 3 | **`git describe --tags --abbrev=0 --match 'v[0-9]*'`** | `git tag -a vMAJOR.MINOR.PATCH -m "Release MAJOR.MINOR.PATCH: "; python build.py` | always the bare base tag → `1.92.4` (distance / dirty state never appear in the version string) | | 4 | **Sentinel** | _(no git, no tags, no flag)_ | `0.0.0+unknown` | The complete public and private release wrappers resolve the version **once at startup**, using the same precedence, and pass `--version ` to `build.py`, `build_uninstaller.py` and `build_installer.py`. A tag created during a long build therefore cannot change the version of later stages. The startup banner prints the pinned value, and an explicit wrapper `--version` reaches every child. `build.py` sets `TLAMATINI_VERSION` only in its own process and descendants. It cannot change the parent shell or sibling processes. When invoking the three standalone scripts manually, pass the same `--version` to each or set the environment variable in the calling PowerShell first. `build_installer.py` compares the package receipt with its requested version before compiling. A mismatch names both versions and requires rebuilding the package. Never edit `runtime-assets.json` to relabel an older frozen application. See the [2026-10-22 diagnosis and regression evidence](docs/changes/2026-10-22-release-version-pinning.md). ### 3.2 Runtime resolution When `Tlamatini.exe` starts (or `python manage.py runserver` in source mode), `agent.version.get_version()` resolves the displayed version like this: | # | Source | When this fires | |---|---|---| | 1 | `agent._version.__version__` | Frozen builds always hit this; source-mode hits it only after you've run `build.py` at least once (since the build emits `_version.py`) | | 2 | `git describe --tags --abbrev=0 --match 'v[0-9]*'` against the working tree (always returns the bare base tag — no dev/dirty suffix) | Source-mode developer who hasn't run `build.py` | | 3 | `"0.0.0+unknown"` sentinel | Last resort — never raises | > The runtime resolution and build resolution intentionally **share the same `git describe` helper** so the version you see in the About dialog during development matches what would be baked in if you ran `build.py` right now. --- ## 4. Step-by-step: how to cut a release This is the canonical happy path. Follow it exactly the first few times until it becomes muscle memory. ### Step 1 — Make sure the working tree is clean and on `main` ```powershell git status # should report "nothing to commit, working tree clean" git checkout main # solo-dev rule: tags always cut from main git pull --ff-only # make sure you're at the tip ``` If `git status` shows changes: commit or stash them first. Building with a dirty tree is technically allowed, but the public version intentionally remains bare SemVer, so `git status` is the only reliable pre-build dirty-tree signal. ### Step 2 — Decide the new version number Use the bump-rules table in §1. Look at the commits since the previous tag if you're unsure: ```powershell git log --oneline (git describe --tags --abbrev=0)..HEAD # (if no tags yet, just: git log --oneline) ``` - All commits are bug fixes? → PATCH (`1.2.0` → `1.2.1`). - At least one new feature? → MINOR (`1.2.0` → `1.3.0`). - Anything that breaks a `.flw` / API / agent contract that already shipped? → MAJOR (`1.2.0` → `2.0.0`). ### Step 3 — Create the annotated tag The release version is **1.92.4**, including the Torrenter queue and Executer fixes. Preserve the existing tag; use a new tag only when Angela requests a new release number. ```powershell git tag -a vMAJOR.MINOR.PATCH -m "Release MAJOR.MINOR.PATCH: " ``` The `-a` flag makes it an **annotated** tag (carries a message + author + date). `--match 'v[0-9]*'` in the resolver is why the leading `v` is required. ### Step 4 — Push the tag ```powershell git push origin vMAJOR.MINOR.PATCH # or push everything: git push --follow-tags ``` ### Step 5 — Build ```powershell python build_complete_public_release.py --version 1.92.4 # For a private keyed release, use build_complete_private_release.py instead. ``` The wrapper pins **1.92.4** and passes it explicitly to all three build stages. Omit `--version` to resolve from the calling environment or reachable Git tag once at startup. Run only in a verified visible foreground console; a real build requires Angela's approval because `build.py` erases `Tlamatini/db.sqlite3` and `dist/`. You'll see this in each script's output: ``` Tlamatini version : 1.92.4 VERSIONINFO file : C:\Development\Tlamatini\Tlamatini.version.txt … Build completed successfully in 240s Version : 1.92.4 ``` The final artefact is **`dist/Tlamatini_Release_v1.92.4/`** — zip and distribute. ### Step 6 — Verify **LaTeXer style releases (added 2026-09-15):** include `latexer.py`, `latexer_styles.py`, `latexer_artwork.py` and `latexer_design.py` together in the template and copied runtime. Check `list_styles` in a copied pool with no TeX on PATH, then run the LaTeXer regression suite and `python scripts/verify_latexer_styles.py --matrix` on a development machine with pdfLaTeX, XeLaTeX, LuaLaTeX and the verifier dependencies. The matrix creates local gallery/report/atlas artifacts; it does not package a TeX distribution. Review failures before releasing, and do not reuse the 2026-09-15 validation snapshot as evidence for later code. The [style guide](Tlamatini/agent/agents/latexer/STYLES.md) describes checks and prerequisites. This feature note does not change the git-tag version contract. After install, the user (or you) should see: - **About dialog**: `Tlamatini v1.92.4` - **Right-click `Tlamatini.exe` → Properties → Details**: ProductVersion = `1.92.4` - **Console banner on startup**: `--- [VERSION] Tlamatini 1.92.4` - **`curl http://localhost:8000/agent/version/`** (after login or with anonymous access since it's open): ```json {"version":"1.92.4","build":"1.92.4","commit":"abc1234","date":"2026-11-01T12:00:00Z","source":"generated"} ``` If any of those four says something different, you missed Step 3 (the tag), or you've got a stale `_version.py` from a previous build — clean it up and re-run `build.py`. --- ## 5. Step-by-step: what happens if you DON'T specify a version This is the most common path during development. The system never blocks you for "no version" and it never decorates the version with distance / commit / dirty suffixes — the displayed version is **always** a clean SemVer. ### 5.1 You ran `build.py` with no tag, no CLI flag, no env var The build script falls through to **precedence #3** (`git describe --tags --abbrev=0 --match 'v[0-9]*'`) — the most recent reachable `v*` tag, stripped to its bare body: | Situation | Tlamatini version | |---|---| | Tags exist; HEAD is exactly on `v1.2.0` | `1.2.0` | | Tags exist; HEAD is 17 commits past `v1.2.0` (clean tree) | `1.2.0` | | Same as above + uncommitted edits | `1.2.0` | | **No tags at all yet** | `0.0.0` | | No tags AND dirty tree | `0.0.0` | | Not a git repo (e.g. running on a download zip) | `0.0.0+unknown` | There is **no `.devN`, no `+gSHA`, no `.dirty`** in any of these outputs. The version you see in the About dialog, the banner, the `.exe` properties, and `/agent/version/` is always a clean `MAJOR.MINOR.PATCH`. If you cut a release on a tree that has uncommitted edits the audit trail lives in git (commit log, `git status`), not in the version string. ### 5.2 You ran `build.py` with no tag, BUT in a shell where `$env:TLAMATINI_VERSION` is set The build script uses that environment value (precedence #2). This is the **only** legitimate path that lets you produce a release-shaped artefact without first creating a git tag. It's intended for CI: a CI job derives the version from a release-trigger event, exports it, then runs all three build scripts. For a manual local build, do **not** rely on the env var — tag first (it's two seconds and creates the audit trail you'll want when triaging a regression later). ### 5.3 You ran `build.py --version 2.0.0-rc.1` on a tree that doesn't have that tag The CLI flag wins (precedence #1). Useful for cutting a release candidate locally **before** you actually commit to the tag — build, smoke-test the `.exe`, then if happy, tag and rebuild. --- ## 6. Pre-releases (alpha / beta / rc) SemVer allows any dot-separated identifiers in the pre-release part. Tlamatini's convention: ``` 2.0.0-alpha.1 # early, expect breakage 2.0.0-alpha.2 2.0.0-beta.1 # feature-complete, debugging 2.0.0-rc.1 # release candidate — bug-fix-only from here 2.0.0-rc.2 2.0.0 # the actual release ``` Tag them exactly the same way: ```powershell git tag -a v2.0.0-rc.1 -m "Release candidate 1 for 2.0.0" git push origin v2.0.0-rc.1 python build.py # → produces dist/Tlamatini_Release_v2.0.0-rc.1/ ``` **Pre-releases sort BEFORE the final release** per SemVer (`2.0.0-rc.2` < `2.0.0`). Windows' "Programs & Features" registry honors this ordering too. --- ## 7. What if I tag the wrong version? **Preserve existing tags and published history.** If `v1.20.0` identifies the wrong commit, correct the source in a new forward commit and use a new unused version, such as `v1.20.1`. Do not delete, move or force-push an existing release tag. Git write operations remain under the user's control; read-only inspection can establish the current tag and commit before a requested release operation. --- ## 8. File-by-file reference What each new/changed file does. Read this only when you need to debug or extend the system. | File | Role | |---|---| | **`Tlamatini/agent/version.py`** | Runtime version resolution. `get_version()`, `get_version_info()`, `derive_version_from_git()`, plus the SemVer parser and the Win32 VERSIONINFO renderer. Has **zero Django dependency** — safe to import from `manage.py` before Django is initialised. | | **`Tlamatini/agent/_version.py`** | **Generated at build time** by `build.py`. Holds `__version__`, `__build__`, `__commit__`, `__date__`. **Gitignored.** Do not edit by hand. | | **`versioning.py`** (repo root) | Top-level shim the three build scripts import. Adds the CLI-arg parser, the precedence resolver (`resolve_build_version`), and the artefact emitter (`emit_build_artifacts`). | | **`Tlamatini/tlamatini/context_processors.py`** | Adds `app_version(_request)` that exposes `{{ version }}` to every Django template. Registered in `settings.py`. | | **`Tlamatini/tlamatini/settings.py`** | One-line addition registering the `app_version` context processor. | | **`Tlamatini/agent/views.py`** | New `version_view`. Open endpoint (no `@login_required`) so it can be used as a health-check. | | **`Tlamatini/agent/urls.py`** | Adds `path('version/', views.version_view, name='version')`. | | **`Tlamatini/agent/templates/agent/agent_page.html`** | The hardcoded `Tlamatini v1.0.0` becomes `Tlamatini v{{ version }}`. | | **`Tlamatini/manage.py`** | Adds `_print_version_banner()` — one `print()` after the tee stream is installed, so both the console AND `tlamatini.log` get a `--- [VERSION] Tlamatini X.Y.Z` line on every startup. | | **`build_complete_public_release.py` / `build_complete_private_release.py`** | Pin the release version before preparation and pass it explicitly to all three child builds. | | **`build.py`** | Resolves the version, writes `agent/_version.py` and `Tlamatini.version.txt`, passes `--version-file=…` to PyInstaller, sets `TLAMATINI_VERSION` for its descendants only, cleans up the .txt at the end. | | **`build_uninstaller.py`** | Honours the pinned `--version` (then environment/Git fallbacks), writes `Uninstaller.version.txt`, passes `--version-file=…` to PyInstaller. | | **`build_installer.py`** | Same pattern as the uninstaller. Also renames the release folder to `Tlamatini_Release_v` so distribution is unambiguous. | | **`.gitignore`** | Adds the generated `_version.py` and the three transient `*.version.txt` files. | --- ## 9. Cheat sheet The one-screen version of this entire document. ``` PICK A NUMBER MAJOR.MINOR.PATCH per SemVer 2.0.0 ─ MAJOR: breaking change ─ MINOR: backward-compat feature ─ PATCH: backward-compat fix TAG IT git tag -a vMAJOR.MINOR.PATCH -m "Release MAJOR.MINOR.PATCH: " git push origin vMAJOR.MINOR.PATCH BUILD IT (VISIBLE) python build_complete_public_release.py --version 1.92.4 Private keyed release: use build_complete_private_release.py. Real builds require approval (database/dist are erased). WHERE IT LANDS dist/Tlamatini_Release_v1.92.4/ About dialog : "Tlamatini v1.92.4" Exe → Properties → Details : ProductVersion = 1.92.4 curl /agent/version/ : {"version":"1.92.4", …} Console banner : --- [VERSION] Tlamatini 1.92.4 NO TAG AT HEAD? Build still works. Version becomes the most recent reachable v* tag, bare (no dev/sha/dirty suffix), or 0.0.0 if no tags at all (0.0.0+unknown if no git). OVERRIDE python build.py --version 2.0.0-rc.1 $env:TLAMATINI_VERSION = "2.0.0-rc.1"; python build.py CORRECT A BAD TAG Preserve the tag and its history. Make a forward fix, then use the next unused version with user authorization. ``` --- ## 10. FAQ **Q: I just want to ship a build. Do I really have to learn all this?** A: No. Run `python build.py` with no flags — you'll get a clean version (the most recent reachable `v*` tag, e.g. `1.1.1`, or `0.0.0` if there are no tags yet) that runs, installs, and shows the right number everywhere. The discipline (Steps 1–6 above) only matters when you want the version string itself to reflect that you cut a fresh release at exactly this commit. **Q: Where does `_version.py` come from on a fresh clone?** A: It doesn't. The file is gitignored. On a fresh clone, `agent.version.get_version()` falls through to the git-derive path until the first time you run `build.py`. The About dialog, banner, and `/agent/version/` will all show the same git-derived value — so the runtime is **never** stuck on a stale `1.0.0`. **Q: Why is there no `.devN` / `+gSHA` / `.dirty` suffix on the version string?** A: Deliberate. The version surface (About dialog, banner, `.exe` properties, `/agent/version/`) is meant to read as a clean SemVer like `1.1.1`. Distance-from-tag and dirty state are git concerns and stay in git (`git status`, `git describe --long --dirty`). If you want the "this isn't a clean release" signal in the build output itself, pass `--version -rc.1` explicitly. **Q: What if `python build.py` is run from a directory that isn't the repo root?** A: The `versioning.py` shim resolves paths from its own file location, not from `os.getcwd()`. Run it from anywhere. **Q: The frozen `.exe` shows `0.0.0+unknown` but I tagged before building.** A: Two common causes: 1. The build was run inside a shell where `$env:TLAMATINI_VERSION` was already set to a stale value — that takes precedence over `git describe`. Clear it: `Remove-Item env:TLAMATINI_VERSION`. 2. `git describe` couldn't see the tag because it's only local. Run `git fetch --tags` (or push the tag) so the build machine sees it. **Q: Can I commit `_version.py` to lock a release?** A: No need. Git tags already lock the release — the tag points at a specific commit and that commit is what gets built. Committing `_version.py` would just create a never-ending stream of "bump version" commits, which is exactly what this system was designed to eliminate. ## About Usage: tag and release boundary (2026-10-10) The Usage dialog and migration 0213 landed on `main` in commit `7460a147`, one commit after the annotated `v1.78.0` tag (`0e6fc72d`). The tagged tree alone does not contain them, but a build of `main` reports the bare `1.78.0` and does — the same shape as `v1.76.0` and the Model Brain. The published v1.78.0 release (marked Latest on 2026-10-10 until v1.82.0 replaced it on 2026-10-12) was built from `main` at `113eddc4`: its zip is byte-identical to the local build and its served files match that commit. The dated evidence and delivery contract are in [the Usage guide](docs/usage-dashboard.md). ## v1.87.0 — Leaner catalog, safer removal, smaller release (carried) **v1.87.0** (tagged 2026-10-18; it also carries v1.86.0, tagged 2026-10-17) came before v1.88.0. Its catalog was **85 workflow agents, 66 wrapped chat agents and 108 built-in tools**: Gatewayer, Gateway-Relayer, Node-Manager and Zavuerer were removed, and migration **0214** deletes their rows and the Zavuerer prompts without renumbering. Removal moves application entries into a same-drive recovery folder (schema 2 journal, **Retry cleanup**, `.tlamatini-removal.json`) instead of copying the payload. `build.py` keeps the carried-Python-only media and browser packages out of the frozen interpreter (`test_release_payload_ownership.py`). About ▸ Usage waits for real data and sends a bodyless `POST /api/me`. `npm run lint:python` runs `scripts/check_python_quality.py`. From v1.86.0: Mover creates a missing destination name as a folder (`_names_a_file()`), and `scripts/architecture_atlas/` rebuilds `Tlamatini-Architecture.pdf` with LaTeXer. The static suffix for that release was `-agent-catalog-1-quality-cleanup-1-usage-status-2`. See [the v1.87.0 release record](docs/changes/2026-10-18-v1.87.0.md). ## v1.85.0 — Refresh, Views and centered avatar (carried) **v1.85.0** (2026-10-16) added Refresh, Views and the centered avatar. `agent_page_canvas.js` owns Refresh source access, complete-text comparison, cancellation and status. Retain browser file handles during the drop event; snapshot-only access cannot refresh a path. PDF replacement stages a ready viewer and keeps its iframe attached at commit. `agent_page_layout.js` exposes `TlamatiniViews.setCanvasVisible`, `isCanvasVisible` and `resetLayout`. Hiding toggles `tlm-canvas-hidden`, preserves the canvas DOM and context, cancels divider gestures and moves focus only when its current region disappears. The account/browser preference is `tlamatini.chat.views.v1.`. `avatar_size.js::setDockedOnly` enforces the hidden-canvas docking rule in pointer, keyboard and public API paths. Reset shows both panes, resets their sizes and docks the portrait without clearing content. The docked frame uses `--tlm-avatar-docked-right` measured from the full Mic/Send row. Its square size and 120 px minimum stay independent of floating geometry. v1.85.0's static suffix was `-avatar-center-1`; Views scripts retain `_views1`. `build_runtime_assets.py` and `copy_source_assets.py` require the Views template, scripts and snapshot harnesses. No migration or dependency was added. See [the release implementation and evidence matrix](docs/changes/2026-10-16-v1.85.0.md), [Refresh](docs/canvas-refresh.md) and [carriage](docs/self-management-carriage.md). ## v1.83.0: historical tag and release (2026-10-14) `v1.83.0` is an annotated tag at `a2914019` (2026-10-14), pushed and published on GitHub the same day as "Tlamatini Release v1.83.0 Win11x64" (marked Latest). It follows `v1.82.0` (`880a335e`, 2026-10-12, published 2026-10-12) and carries the three changes made after it: `91ff8453` (a wrongly worded image/video request is not a fatal error), `63a62cc1` (the docked avatar follows both composer dividers) and `a2914019` itself (the page-wide file-drop router). The version resolves to the bare `1.83.0` for that historical release. The contract of the router is in [the frontend guide](docs/claude/frontend.md). ## v1.82.0: tag and release boundary (2026-10-12) `v1.82.0` is an annotated tag at `880a335e` (2026-10-12), pushed and published on GitHub the same day as "Tlamatini Release v1.82.0 Win11x64" (it was marked Latest until v1.83.0 replaced it on 2026-10-14). The two tags before it, `v1.79.0` (`5f549868`) and `v1.80.0` (`82099963`), both 2026-10-11, were pushed without a published release, and **no `v1.81.0` tag exists** — a skipped number is allowed; SemVer only requires that versions increase. Read `gh release list` for publication, and the frozen code itself when it matters whether a change shipped. ## Release type and combined builder — 2026-11-07 Complete private/public wrappers embed their type in `agent._version`. `tlamatini.log` starts with the version and `PRIVATE` or `PUBLIC`; source runs report `DEVELOPMENT`. Before either build starts, the combined launcher previews each existing resolver and emitter, compares the exact application-reported numbers, and pins one shared `--version` for both. Environment overrides are honored; tags on HEAD are not required. `--Override_versioning X.Y.Z` selects one common number. See the [combined builder guide](docs/combined-release-builder.md).