Table of Contents
-
Mojo 1.0 migration wave: what changed, what worked, and what’s next
- Executive summary
- Why this migration now
- What was delivered
- Alignment with agentic engineering practice
- Distribution stance for this phase
- Public release scope for this wave
- Current status
- What happens next
- Appendix A: Repo-level technical notes
- Appendix B: Practical migration sequence used
- Appendix C: mojo-toml pilot gotchas under Mojo 1.0
- Appendix D: Wave A gotchas and fix patterns (mojo-asciichart, mojo-dotenv, mojo-ini, mojo-yaml)
- Cross-repo mechanical changes that were consistently required
- mojo-dotenv specific notes
- mojo-ini specific notes
- mojo-yaml specific notes
- Appendix E: Wave B gotchas and fix patterns (mojo-benchsuite)
- Appendix F: Consumer install policy examples
Mojo 1.0 migration wave: what changed, what worked, and what’s next
Executive summary
Over this migration wave, I moved my mojo-* libraries onto one consistent Mojo 1.0 baseline.
The goal was practical: reduce release friction, keep each package usable, and stop the “works in repo A, breaks in repo B” cycle.
The result is a cleaner operational path, better cross-repo consistency, and a clear public release set aligned to Mojo 1.0.
This post keeps the main story concise. Full technical notes are in the appendices.
Why this migration now
The ecosystem has been moving quickly, and the repos had drifted in small but painful ways: packaging paths, validation assumptions, and compatibility handling.
None of those issues was huge on its own. Together, they created avoidable drag in day-to-day delivery.
So the migration focused on three things:
- one release approach across repos,
- one repeatable validation posture,
- and one version line for this 1.0 phase.
What was delivered
1) Operational consistency
For package-oriented repos, recipe handling and validation flow were aligned so local scripts, CI, and docs all reference the same source of truth.
Code-quality automation was also standardised on prek as the git-hook runner, while retaining .pre-commit-config.yaml compatibility.
2) Compatibility uplift
The key Mojo 1.0 breakpoints were addressed, including stricter API surfaces and checked-raises related test stabilisation.
3) Release alignment
All migrated repos now sit on a shared 0.9.1 line with corresponding tags, so consumers can target a coherent set of builds.
Alignment with agentic engineering practice
This migration broadly followed the pattern in Modular’s write-up on building Mojo projects with AI agents:
- human-led architecture and product judgement,
- agent-led execution for repetitive, cross-repo, and boilerplate-heavy work.
Where I deliberately diverged: distribution policy. Because packaging is still evolving, the practical choice for now is controlled 0.9.1 releases with explicit consumer pinning.
Reference:
- https://www.modular.com/blog/how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents
Distribution stance for this phase
For these migrated DataBooth libraries, the recommendation is to consume the current Mojo 1.0-aligned line and avoid fallback to older 26.x-era community artefacts.
In practice:
- prefer DataBooth-hosted packages for these libraries,
- pin versions explicitly (
==0.9.1is the safest default), - use modular-community for other dependencies only where needed.
Public release scope for this wave
This public release now focuses on six libraries:
mojo-tomlmojo-inimojo-yamlmojo-dotenvmojo-asciichartmojo-benchsuite
Current status
This closes the current migration execution wave across:
mojo-tomlmojo-inimojo-yamlmojo-dotenvmojo-asciichartmojo-benchsuite
What happens next
Near term, the plan stays simple and low-risk:
- publish and support the six-library
0.9.1release cleanly, - keep release mechanics repeatable,
- revisit packaging strategy once the ecosystem settles further.
Appendix A: Repo-level technical notes
mojo-ini, mojo-yaml, mojo-dotenv, mojo-asciichart
- Consolidated recipe-path handling and pre-submit flow.
- Synced migration-sensitive docs with the operational command path.
- Migrated local hook commands from
pre-committoprek. - Retained passing validation with only non-blocking tool warnings.
Appendix B: Practical migration sequence used
- Create or switch to
feature/mojo-1.0b1-migration. - Resolve packaging and tooling path consistency first.
- Run repo-native tests and validation.
- Fix compiler and runtime issues in clusters.
- Update docs in the same change set.
- Re-run full validation before push.
Appendix C: mojo-toml pilot gotchas under Mojo 1.0
Recursive value model breakage
The most significant compiler blocker in the pilot was recursive storage in TomlValue.
Direct fields like List[TomlValue] and Dict[String, TomlValue] now fail with a Deinitable constraint error under Mojo 1.0.
The working pattern was to store recursive values as boxed entries and implement explicit deep-copy + cleanup behaviour in the value type.
Secondary stdlib/source updates
Two smaller migration fixes were also required:
- update
mathimports tostd.math, - replace
len(String)usage with explicit string-length APIs (byte_length()in numeric-prefix checks).
Validation evidence
After these fixes, pixi run test-all passed all suites in mojo-toml on Mojo 1.0.
Appendix D: Wave A gotchas and fix patterns (mojo-asciichart, mojo-dotenv, mojo-ini, mojo-yaml)
Cross-repo mechanical changes that were consistently required
- Replace legacy
fndeclarations withdefacross sources, tests, examples, and packaging smoke tests. - Move imports to current stdlib paths where required (
std.math,std.python,std.pathlib,std.os). - Replace ambiguous string operations (
len(String)and direct string slicing) with explicit Mojo 1.0 APIs (byte_length(),s[byte=...]). - Add
raisesannotations through test call chains where parser and loader APIs can throw.
mojo-dotenv specific notes
pathlibandosimports needed migration tostd.pathlibandstd.os.- Parser internals required UTF-8-safe string handling updates in export-prefix stripping and empty-string checks.
- Validation result:
pixi run test-allpassed all 11 suites;pixi run build-packagesucceeded (warnings only).
mojo-ini specific notes
- Lexer had hidden
len(self.input)checks that needed conversion to character-buffer length checks (len(self.chars)). - One string-length assertion in error tests needed conversion to
byte_length()to satisfy Mojo 1.0 string semantics. - Validation result:
pixi run test-allpassed all 5 suites;pixi run build-packagesucceeded (warnings only).
mojo-yaml specific notes
- The initial
YamlValuerecursive model (List[YamlValue]/Dict[String, YamlValue]) failed under Mojo 1.0 with Deinitable constraints, mirroring the earlier TOML pilot issue. - The fix pattern was the same as
mojo-toml: boxed recursive storage with explicit deep-copy and deinit ownership handling. - A follow-up test adaptation was needed where debug tests directly traversed sequence internals; accessor-based reads avoided pointer-type misuse.
- Validation result:
pixi run test-allpassed all 15 suites;pixi run build-packagesucceeded (warnings only).
Appendix E: Wave B gotchas and fix patterns (mojo-benchsuite)
mojo-benchsuitestarted from a nightly-channel posture; migration switched it to stable Mojo 1.0 channels and explicit runtime pinning.- Benchmark callback wiring needed a Mojo 1.0 API update: thin benchmark functions now run via explicit callable parameters (
auto_benchmark(name, benchmark_func, min_runtime_secs)). - Legacy helpers like
String.ljustand implicitlen(String)usage required replacement (byte_length()plus local padding helper). - Import paths also needed modernisation in benchmark internals (
std.time,std.sys,std.python). - Validation result:
pixi run test(adaptive smoke benchmark) passed,pixi run bench-allcompleted all six benchmark suites successfully.
Appendix F: Consumer install policy examples
Option 1: Packaged installs via a DataBooth channel (recommended)
For packaged releases, use one package channel URL plus explicit pins:
[project]
channels = [
"conda-forge",
"https://conda.modular.com/max",
"<DATABOOTH_CONDA_CHANNEL_URL>"
]
[dependencies]
mojo-toml = "==0.9.1"
mojo-ini = "==0.9.1"
mojo-yaml = "==0.9.1"
mojo-dotenv = "==0.9.1"
mojo-asciichart = "==0.9.1"
mojo-benchsuite = "==0.9.1"
Important: <DATABOOTH_CONDA_CHANNEL_URL> is the package index/channel endpoint, not individual GitHub repository URLs.
If modular-community is present for other packages, explicit pins prevent accidental resolution to older incompatible builds for these libraries.
Option 2: Source consumption from GitHub repos (follow-up or experimental)
If you want to consume directly from source, add each library repo and include its src path when running Mojo:
git submodule add https://github.com/databooth/mojo-toml vendor/mojo-toml
git submodule add https://github.com/databooth/mojo-ini vendor/mojo-ini
git submodule add https://github.com/databooth/mojo-yaml vendor/mojo-yaml
git submodule add https://github.com/databooth/mojo-dotenv vendor/mojo-dotenv
git submodule add https://github.com/databooth/mojo-asciichart vendor/mojo-asciichart
git submodule add https://github.com/databooth/mojo-benchsuite vendor/mojo-benchsuitemojo \
-I vendor/mojo-toml/src \
-I vendor/mojo-ini/src \
-I vendor/mojo-yaml/src \
-I vendor/mojo-dotenv/src \
-I vendor/mojo-asciichart/src \
-I vendor/mojo-benchsuite/src \
your_app.mojo