{"slug": "modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents", "title": "Modular: How I built a pure Mojo app (and 10 libraries) with AI agents", "summary": "A developer built a production pastebin service called mobin using only the Mojo programming language, creating 10 supporting libraries and a documentation tool from scratch in a few weeks with AI coding agents. The project demonstrates that AI agents can scale from porting single components to building entire greenfield ecosystems, with the developer handling architecture and design while agents wrote bindings, tests, and cross-repo upgrades. The effort stress-tests Mojo 1.0's beta capabilities across networking, persistence, serialization, and other layers, showing the language can support full-stack applications.", "body_md": "A few days ago Modular published [Translating to Mojo via AI Agents](https://www.modular.com/blog/translating-to-mojo-via-ai-agents), where Brad walks through using the official [ modular/skills](https://github.com/modular/skills) to translate a CUDA softmax kernel into portable Mojo and to upgrade five community projects to\n\n`mojo == 1.0.0b1`\n\nin a single agent pass. That post answers \"can an agent port one well-defined thing to Mojo today?\" The answer is yes.**This post answers the next question**: how far does that scale? With the same skills, the same `1.0.0b1`\n\ncompiler, and a few weeks of side-project time, can one developer plus an agent stand up a whole greenfield ecosystem? mobin and its 10 libraries are the result.\n\nI shipped a production pastebin service (HTTP server, WebSocket live feed, SQLite database, JSON serialization, URL routing, gzip compression, etc.) with zero Python in the backend. It is all [Mojo](https://docs.modular.com/mojo/). You can try it right now at [mobin.fly.dev](http://mobin.fly.dev/).\n\nThe story is not the pastebin. The story is that to build this one app, I ended up building 10 Mojo libraries and a documentation tool from scratch, all with AI coding agents (and [agent skills](https://www.modular.com/blog/translating-to-mojo-via-ai-agents)), as a side project. The whole thing took just a few weeks of tinkering, rather than months of dedicated effort.\n\nThis is what [Andrej Karpathy](https://karpathy.bearblog.dev/sequoia-ascent-2026/) recently called *Agentic Engineering*. From his [Jan 26 2026 X post](https://x.com/karpathy/status/2015883857489522876):\n\nI rapidly went from about 80% manual+autocomplete coding and 20% agents in November to 80% agent coding and 20% edits+touchups in December. I really am mostly programming in English now... This is easily the biggest change to my basic coding workflow in ~2 decades of programming and it happened over the course of a few weeks.\n\nThat ratio matches my experience. I designed the APIs and made the architecture calls. The agent wrote the FFI bindings, the test suites, and most of the cross-repo upgrade work. Karpathy frames the same shift at Sequoia Ascent 2026 as the move from \"vibe coding\" (which raises the floor) to \"Agentic Engineering\" (which raises the ceiling): more discipline, more orchestration, *more taste*, and a lot less typing.\n\nChris Lattner makes the same point from the platform side in [What the Claude C Compiler reveals about the future of software](https://www.modular.com/blog/the-claude-c-compiler-what-it-reveals-about-the-future-of-software): AI is moving from code completion to engineering participation, the implementation work is getting automated, and the scarce skills are now architecture, design, and judgment.\n\nThis was a deliberate exercise. [Mojo 1.0 is here in beta](https://www.modular.com/blog/the-path-to-mojo-1-0), and I wanted to stress-test the ecosystem on `mojo == 1.0.0b1`\n\nby building something that touches every layer: networking, persistence, serialization, config, testing, documentation. Mojo can already do much more than people think.\n\n## What we built\n\n[mobin](https://github.com/ehsanmok/mobin) is a pastebin service. You paste code, get a shareable link, and there is a live feed of new pastes via WebSocket. The backend is a 1.1 MB AOT-compiled Mojo binary running on a free-tier [Fly.io](http://fly.io/) `shared-cpu-1x`\n\n256 MB VM, behind [flare](https://github.com/ehsanmok/flare)'s multi-worker reactor (one pthread per CPU core, so one worker on the production VM, N on multi-core hosts), with a middleware stack that does gzip compression and ETag-based 304 caching. App-side latency in `fly logs`\n\nis 1 ms per request.\n\nTo build it, I needed libraries that did not exist yet or did not support the exact required features. So I built them:\n\nLibrary | What it does | Link |\n|---|---|---|\nflare | Full networking stack for Mojo🔥 |\n|\n\n**json**[github.com/ehsanmok/json](http://github.com/ehsanmok/json)** sqlite**[github.com/ehsanmok/sqlite](http://github.com/ehsanmok/sqlite)** morph**[github.com/ehsanmok/morph](http://github.com/ehsanmok/morph)** mozz**[github.com/ehsanmok/mozz](http://github.com/ehsanmok/mozz)** uuid**[github.com/ehsanmok/uuid](http://github.com/ehsanmok/uuid)** tempo**[github.com/ehsanmok/tempo](http://github.com/ehsanmok/tempo)** envo**[github.com/ehsanmok/envo](http://github.com/ehsanmok/envo)** mojodoc**[github.com/ehsanmok/mojodoc](http://github.com/ehsanmok/mojodoc)** pprint**[github.com/ehsanmok/pprint](http://github.com/ehsanmok/pprint)*Note: If you’re deeply familiar with **Mojo**, you might be asking yourself why I didn’t use community libraries like **EmberJson** for Json or **slight** for SQLite, two great Mojo community projects. I wanted to both challenge my agent to build what it needed precisely with full feature completeness and also ensure compatibility with the latest mojo versions. I wanted to test our **Mojo skills **to their limits. *\n\nHere is how they fit together:\n\nA few things to notice. There are only 3 compile-time dependency edges between the Mojo libraries: [flare](https://github.com/ehsanmok/flare) depends on [json](https://github.com/ehsanmok/json), [sqlite](https://github.com/ehsanmok/sqlite) depends on [morph](https://github.com/ehsanmok/morph), [envo](https://github.com/ehsanmok/envo) depends on morph. The leaf nodes (json, morph, [uuid](https://github.com/ehsanmok/uuid), [tempo](https://github.com/ehsanmok/tempo)) have zero ecosystem dependencies. They are the foundation, and everything else composes cleanly on top.\n\n[mozz](https://github.com/ehsanmok/mozz) (fuzz testing) and [mojodoc](https://github.com/ehsanmok/mojodoc) (documentation) are not runtime dependencies; they are development-time tools that plug into the ecosystem. Even the quality and documentation tooling was built from scratch.\n\n11 projects. One developer designing the APIs and testing approach with AI agents doing the heavy lifting on boilerplate.\n\n## How AI agents accelerated everything\n\nI used [Cursor](https://cursor.com/) with [Mojo agent skills](https://github.com/modular/skills) throughout the project. The workflow generally followed the usual agentic development:\n\n- I would describe what a library should do, its API surface, the key types, how it should feel to use according to my taste, in plan mode and iterate a couple of times until I was happy with the approach.\n- The agent would scaffold the package structure, write the core logic, and generate an initial test suite.\n- I would review the API design, adjust naming and signatures, and push back on anything that felt un-Pythonic.\n- The agent would fill in edge cases, add more tests, write docstrings.\n- Repeat.\n\nWhere agents saved the most time: FFI boilerplate. `sqlite`\n\nhas ~40 function pointer bindings to `libsqlite3`\n\n. `json`\n\nwraps simdjson's C API and also has a native Mojo CPU backend. `uuid`\n\ncalls into the OS random number generator. Writing that code by hand is tedious and error-prone. The agent generated it correctly on the first or second try every time.\n\nLibrary research was the other big category. Before writing any new library I would point the agent at the prior art and ask for a synthesis. [morph](https://github.com/ehsanmok/morph)'s compile-time-reflection serde is a direct port of [reflect-cpp](https://github.com/getml/reflect-cpp)'s design. [flare](https://github.com/ehsanmok/flare)'s middleware, router, typed-extractor, and per-worker `SO_REUSEPORT`\n\nlistener shapes converged on what works in actix_web, hyper, and axum on the Rust side, and FastAPI on the Python side. The agent reads design docs faster than I do and surfaces when two libraries disagree on a primitive.\n\nTest generation was another big win. I would describe the behaviour I wanted tested, and the agent would produce 15 to 20 test functions with edge cases I had not thought of. Across the ecosystem, there are hundreds of tests, and the agent wrote most of them.\n\nCross-repo dependency updates were surprisingly good too. When the time came to bump every library to `mojo = \"==1.0.0b1\"`\n\n, I told the agent: \"update all repos to pin mojo 1.0.0b1 according to the changelog, fix any breakage, test, and push.\" It went through each repo, updated the pin, fixed compilation errors, ran tests, committed, and pushed. The whole bump went through every repo as one mostly-mechanical pass. The `pixi-build`\n\nsource-build dependency model below is the other reason that pass was as smooth as it was.\n\nWhat still needed my judgment: API design. Architecture trade-offs. Debugging compatibility issues across nightly transitions. The agent is good at executing a well-defined plan; the human decides what the plan should be.\n\n## API design: adopt from Python's best with Mojo flavour\n\nThe guiding principle for every library was: look at the Python API that developers already know and love, then replicate that feel in Mojo. Do not invent new patterns. Mojo gives you systems-level performance, but the call site should read like the Python equivalent. That is how you ease adoption. A Python developer should be able to read Mojo code and immediately know what it does.\n\nThe playbook is simple. Before designing any library, I looked at the established Python API for that domain and used it as the blueprint. Mojo makes it easy because so many of its constructs are themselves Pythonic.\n\n### Data models: `@dataclass`\n\nbecomes `@fieldwise_init`\n\nstruct\n\nPython developers define data with `@dataclass`\n\n. [mobin](https://github.com/ehsanmok/mobin)'s `Paste`\n\nstruct uses the same shape:\n\nIf you have used `@dataclass`\n\nin Python, the synthesized constructor will look familiar, but `@fieldwise_init`\n\nis narrower than `@dataclass`\n\nby design. It generates **only** the positional fieldwise `__init__`\n\nand nothing else (see more details in [Mojolang docs](https://mojolang.org/docs/reference/decorators/fieldwise-init/)).\n\n### Flare's flavour: Rust reactor, Python ergonomics\n\n[flare](https://github.com/ehsanmok/flare) is a thread-per-core reactor (`kqueue`\n\n/ `epoll`\n\n) with a FastAPI-shaped handler API on top. Three layers, three sets of prior art.\n\n**Bottom (reactor).** One event loop per worker, no thread per connection, no locks on the hot path. Same shape as `tokio`\n\nand `nginx`\n\n. The default multi-worker mode binds N listeners with `SO_REUSEPORT`\n\n(matches `actix_web`\n\n); `FLARE_REUSEPORT_WORKERS=0`\n\nswitches to a tokio-style shared accept (matches `hyper`\n\n/ `axum`\n\n). On the 4-worker bench, flare posts the cleanest p99.99 of the four.\n\n**Top (handlers).** `def handler(req: Request) -> Response`\n\n, the signature Flask and FastAPI use. `Router.get(\"/path\", handler)`\n\nregisters it. `from flare.prelude import *`\n\npulls `Request`\n\n, `Response`\n\n, `Router`\n\n, `HttpServer`\n\n, `ok`\n\n, `ok_json`\n\n, `not_found`\n\n, `bad_request`\n\n. Hello-world:\n\n**Middle (composition).** Typed extractors (`PathInt[\"id\"]`\n\n, `QueryInt`\n\n, `HeaderStr`\n\n, `Form[T]`\n\n, `Json[T]`\n\n, `Cookies`\n\n) are struct fields parsed before `serve`\n\nruns; missing or malformed input becomes a sanitized 400. Same model as `axum`\n\n's extractors and FastAPI's typed params. Middleware (`Logger`\n\n, `RequestId`\n\n, `CatchPanic`\n\n, `Compress`\n\n, `Conditional`\n\n, `Cors`\n\n) nests like `tower`\n\nlayers, except the chain monomorphises to one direct call sequence per handler with no vtable dispatch. Shared state uses `App[S]`\n\n/ `State[S]`\n\n, the same shape as `actix_web`\n\n's `Data< T>`\n\nand `axum`\n\n's `State < S>`\n\n.\n\nTransports (`WsClient`\n\n, `TcpStream`\n\n, `TlsConnector`\n\n, `UdpSocket`\n\n) are context managers, so Python's `with`\n\nblock runs the cleanup:\n\nmobin uses every layer.\n\n### Database: `sqlite3`\n\nbecomes sqlite\n\nPython's `sqlite3`\n\nmodule is one of the most widely used APIs in the standard library. The [sqlite](https://github.com/ehsanmok/sqlite) library mirrors it directly:\n\n`Database(\":memory:\")`\n\n, `execute()`\n\n, `prepare()`\n\n, parameterized queries with `?`\n\nplaceholders. These are the same patterns every Python developer uses. The ORM layer on top follows the same principle: define a struct, and the library handles table creation and CRUD.\n\n### JSON: the `json`\n\nmodule becomes the json library\n\nPython's `json.loads()`\n\nand `json.dumps()`\n\nare probably the most universally known API in the entire ecosystem. The [json](https://github.com/ehsanmok/json) library mirrors them exactly:\n\nSame function names, same behavior. `load()`\n\nreads from a file handle, `dump()`\n\nwrites to one. A Python developer does not need to learn anything new.\n\nBut here is where Mojo's parametric system adds something Python cannot do. The same `loads`\n\nfunction accepts a compile-time `target`\n\nparameter that selects the parsing backend:\n\nThe API surface is identical to Python's `json`\n\nmodule. The parametric `[target=...]`\n\nis the Mojo flavour: you opt into a faster backend at compile time without changing the call site. Python cannot express this. You would need separate libraries or runtime flags. In Mojo, it is one function with a compile-time switch.\n\n### Serialization: Pydantic becomes morph\n\nPydantic taught Python developers that serialization should be automatic from your model definition. [morph](https://github.com/ehsanmok/morph) does the same thing through compile-time reflection, but across multiple formats from a single struct definition:\n\nOne struct, three output formats. No schema definitions, no manual field mapping, no format-specific annotations. morph reflects over struct fields at compile time and generates the serialization code for each format. The mental model is identical to Pydantic's `model_dump()`\n\nand `model_validate()`\n\n, extended across JSON, TOML, and CSV without writing a single adapter.\n\n### Fuzz testing: Hypothesis / atheris become mozz\n\nPython developers who use [Hypothesis](https://hypothesis.readthedocs.io/) for property-based testing or [atheris](https://github.com/google/atheris) for mutation fuzzing will recognise [mozz](https://github.com/ehsanmok/mozz) immediately:\n\nMutation fuzzing in one call, just like atheris. Property-based testing with automatic shrinking, just like Hypothesis. Define a property, provide a generator, and mozz minimises failing inputs to the smallest reproducing case.\n\nThis is a deliberate strategy, not just a stylistic preference. Mojo's biggest adoption advantage is that Python developers already outnumber every other systems programming community. If your Mojo library feels like the Python library they already use, the learning curve drops to nearly zero. They get the familiar API with compiled performance, SIMD, and `comptime`\n\nunderneath. You do not need to sell them on a new paradigm. You just need to show them the same patterns running faster.\n\n## Testing\n\nEvery library follows the same testing pattern. Tests use `std.testing`\n\nassertions, run against in-memory fixtures, and need no external test runner.\n\nHere is a typical test from [mobin](https://github.com/ehsanmok/mobin):\n\n`Database(\":memory:\")`\n\ngives each test a fresh SQLite database. No shared state, no cleanup, no fixtures to manage. Tests run in parallel without interfering with each other.\n\nFor libraries that handle untrusted input ([flare](https://github.com/ehsanmok/flare), [sqlite](https://github.com/ehsanmok/sqlite)), I use [mozz](https://github.com/ehsanmok/mozz) for fuzz testing. mozz has two modes.\n\nMutation fuzzing throws random byte sequences at your parser and checks that it raises cleanly instead of panicking:\n\nProperty-based testing generates typed values and verifies invariants:\n\nWhen a property fails, mozz automatically minimises the failing input to the smallest reproducing case. This caught real bugs in sqlite's text handling and flare's HTTP header parsing.\n\nCI runs on every push via GitHub Actions with [Pixi](https://pixi.sh/):\n\nTwo lines of YAML after checkout. The CI config is identical across all Mojo repos.\n\n## Consistent structure across every library\n\nEvery library in the ecosystem follows the same layout:\n\nSame CI template everywhere: `setup-pixi`\n\nthen `pixi run tests`\n\n, matrix across `ubuntu-latest`\n\nand `macos-15`\n\n. Same testing pattern: `std.testing`\n\nassertions, in-memory fixtures, one `def main()`\n\nentry point per test file.\n\nThis consistency matters more than it might seem. When every library works the same way, you can contribute to any of them without learning a new project structure. The AI agent can also work faster because the patterns are predictable.\n\n## Pixi as the package manager\n\nIf you have ever used [uv](https://docs.astral.sh/uv/), then [pixi](https://pixi.sh/) feels like uv++. For PyPI dependencies (added through `--pypi`\n\n) pixi uses uv under the hood, and for Conda packages it uses its own fast Rust solver. It is the right tool for Mojo projects for two specific reasons.\n\nThe first is `pixi-build`\n\n, which is the source-build path for Mojo libraries. With `preview = [\"pixi-build\"]`\n\nenabled, pixi resolves your git-tagged Mojo dependencies through [ rattler-build](https://prefix-dev.github.io/rattler-build/), which builds each library from source against the consumer's declared\n\n`mojo`\n\nversion. There is no Conda channel for Mojo packages and no pre-built `.mojopkg`\n\nto ship. Every library in the graph compiles against the same compiler your project pins, which means two libraries cannot disagree on what Mojo version they were built with. The MLIR-bytecode incompatibility trap that used to haunt early Mojo development is gone in this model.The second is that `pixi.lock`\n\npins every transitive dependency to exact builds. Two developers running `pixi install`\n\nget byte-identical environments. Combined with source builds, one declared `mojo == 1.0.0b1`\n\nflows down through the entire graph reproducibly.\n\nHere is what [mobin](https://github.com/ehsanmok/mobin)'s actual `pixi.toml`\n\nlooks like:\n\nEvery dependency is a git ref pointing at a tagged release. [flare](https://github.com/ehsanmok/flare) is the most mature library and sits at v0.7.0 with the multi-worker reactor, middleware, and typed-extractor work; the rest of the ecosystem sits at v0.1.x as smaller, focused libraries. System libraries like openssl, ca-certificates, and zlib still come from Conda channels because they are not Mojo packages, and pixi handles that side fine.\n\nCold `pixi install`\n\nfor the entire mobin project (Mojo compiler, all 8 Mojo deps, system libs) takes under 30 seconds with the source-build pipeline warm. Warm installs are near-instant.\n\n## Build on Mojo 1.0.0b1 today\n\nMojo’s Beta-1 is shipped. The semver promise is real: packages built against 1.0.x will keep working across the 1.x series. [The path to Mojo 1.0](https://www.modular.com/blog/the-path-to-mojo-1-0) post lays out the rest of the story.\n\nThe ecosystem needs libraries. When 1.0 ships, projects that already exist become the foundation everyone else builds on. HTTP servers, database bindings, serialization, testing tools, CLI frameworks. All of these should exist, and the window to be early is right now.\n\nI have a belief about this: year one after Mojo 1.0 will look like at least year five after Rust 1.0 if we leverage Agentic Engineering correctly. Rust's ecosystem took years to build because every crate was written by hand. With Agentic Engineering, one developer can ship a well-tested library in days with their own taste, instead of months. I built 10 libraries and a production app in weeks. Multiply that across a community of developers all working the same way and the ecosystem fills out fast.\n\nThe approach works for anyone. Pick a gap in the ecosystem. Use Pixi for package management with `preview = [\"pixi-build\"]`\n\nfor source builds. Follow a consistent project structure. Plan first, then write Pythonic APIs. Test with `std.testing`\n\nand mozz. Set up CI with GitHub Actions. Ship it.\n\nAll of the code from this project is MIT-licensed and on GitHub:\n\n[mobin](https://github.com/ehsanmok/mobin): the production pastebin service[flare](https://github.com/ehsanmok/flare): full networking stack for Mojo🔥[json](https://github.com/ehsanmok/json): high-performance JSON library for Mojo🔥 with GPU acceleration[sqlite](https://github.com/ehsanmok/sqlite): SQLite FFI plus ORM[morph](https://github.com/ehsanmok/morph): reflection-driven serde[uuid](https://github.com/ehsanmok/uuid): UUID v4/v7[tempo](https://github.com/ehsanmok/tempo): timestamps and durations[envo](https://github.com/ehsanmok/envo): typed config loading[pprint](https://github.com/ehsanmok/pprint): debug pretty-printing[mozz](https://github.com/ehsanmok/mozz): fuzz and property testing[mojodoc](https://github.com/ehsanmok/mojodoc): API documentation generator\n\nKarpathy described the December 2025 inflection as the moment agents crossed \"some kind of threshold of coherence\" and caused a phase shift in software engineering. That is what made all of this possible in weeks, on a fresh 1.0 ecosystem. Fork anything, build on top, and ship something on 1.0.0b1.\n\nShare what you build. The Mojo community lives on the [Modular forum](https://forum.modular.com/): [Community Showcase](https://forum.modular.com/c/community-showcase/8) for projects on MAX and Mojo, [Mojo](https://forum.modular.com/c/mojo/7) for language questions. The ecosystem fills out fastest when the work is in the open.", "url": "https://wpnews.pro/news/modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents", "canonical_source": "https://www.modular.com/blog/how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents", "published_at": "2026-05-19 00:00:00+00:00", "updated_at": "2026-05-29 23:57:39.131808+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-products", "ai-infrastructure", "generative-ai"], "entities": ["Modular", "Mojo", "Brad", "Andrej Karpathy", "mobin", "fly.dev", "CUDA", "SQLite"], "alternates": {"html": "https://wpnews.pro/news/modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents", "markdown": "https://wpnews.pro/news/modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents.md", "text": "https://wpnews.pro/news/modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents.txt", "jsonld": "https://wpnews.pro/news/modular-how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents.jsonld"}}