I design systems end to end, then run them in production.
baryo.dev ·
@BaryoDev ·
writing ·
email
14 years in production software. I design systems end to end and then run them: an event-sourced multi-tenant CMS, the deploy tooling it ships through, the libraries underneath it, and the front end on top. Strongest in .NET, though most of what I ship is not.
The decisions are the work. Event sourcing over CRUD and what that costs on the read side. Modules compiled in rather than loaded at runtime, because a plugins folder is a place where writing a file runs code. One cheap VM instead of a platform, and what that trades away. Each of those is written up with the reasoning, not just the outcome.
@BaryoDev is 30 public repositories across C#, TypeScript, Go and JavaScript, all open source and self-hostable. No paid tier, no seat cap, no metered anything.
Eleven merged fixes and five accepted bug reports in libraries I run in production, across four repos totalling 13k stars. Each was found by using the thing, not by browsing for issues. The badges are live searches, so they answer for themselves.
| Project | What was wrong | |
|---|---|---|
| umbraco/Umbraco-CMS | ★5.2k | Instances sharing a database failed each other's requests registering the same OpenIddict application. #23599, #23727, shipped in 17.7 and 18.2 |
| testcontainers/testcontainers-dotnet | ★4.4k | MongoDB replica-set init was not idempotent, so a reused container hung against a one-hour timeout. #1731, #1735. A reused Couchbase container then stalled on the first step of configuring a cluster that was already configured. #1736 |
| JasperFx/marten | ★3.5k | HardDeleteWhere could not remove already soft-deleted rows, and returned cleanly either way. #5215, #5202, #5240. The parameterised MatchesJsonPath overload threw on every call, so no one could have been using it. #5289. The pgvector docs still described a recall cap the library had stopped applying, and the caveat that replaced it was wrong for hybrid search. #5467 |
| JasperFx/jasperfx | core | The event loader claimed a ceiling it had never scanned, so a fully skipped batch could advance past events and lose them permanently. Reported on Marten, then fixed at the source. #670 |
Most of these reports were fixed by the projects' own maintainers rather than by me, which is the part worth pointing at: the report carried enough evidence for someone else to act on it.
| Reported | Outcome |
|---|---|
| marten#5239 | A projection's event loader reported a ceiling it never scanned, so events could be skipped permanently. Confirmed by the maintainer as silent, permanent data loss, fixed in #5242, and I then fixed the same flaw in the shared library underneath in jasperfx#670. |
| marten#5234 | Event masking and stream compaction wrote across tenants under partitioned event tenancy. Fixed in #5236. |
| marten#5222 | An audit reported a check as passing that it had not actually performed. Fixed in #5231. |
| umbraco#23598 | The Delivery API's subscriber guard can never match, because the server role is not elected until after the boot notification it reads from. Fixed by an Umbraco developer in #23801, a change spanning 21 files, merged and queued for 17.8. |
| testcontainers#1732 | A readiness check counted log lines and compared the count for equality, so a container either hung against a one-hour timeout or was reported ready before the server was listening. Two other users confirmed it independently. Fixed in #1735. |
Sometimes the useful contribution is not a pull request. On marten#5457, someone else's leak report, I could confirm half of it and disprove the other half, and said so rather than opening a fix I could not demonstrate. The maintainer's own #5466 opens by crediting that comment: "right on both counts and shaped this."
upstream-fixes writes each one up, and carries a runnable reproduction for marten#5215 against published NuGet packages, so you can watch that bug appear on one version and disappear on the next rather than take my word for it.
Open-source headless CMS for .NET. Event-sourced on Marten and PostgreSQL, multi-tenant, user-defined content schemas, 13 opt-in modules, an event-triggered workflow engine, and a Next.js admin UI.
127 endpoints and 2,284 tests, run against real PostgreSQL and MinIO through Testcontainers. On .NET 10 and Marten 9. MPL-2.0, and every module is included rather than sold separately.
4.0.0 shipped in September 2026 to NuGet, GHCR and Docker Hub: four auth and file-access holes closed, GDPR erasure, tenancy resolved from a domain, content references, multi-architecture non-root images, an SBOM, and a WCAG pass.
The claims are gates rather than sentences. CI restores a backup, upgrades a 3.x database, applies the Kubernetes manifests, generates the SBOM, scaffolds a module from the template and builds it, resolves every compose file, and refuses an image tag that is amd64-only.
Live at playground.baryo.dev/barakocms. Console: barakoBrew, for designing content types, roles, workflows and integrations against the API. Typed client: barako-client. baryo.dev itself is rendered from it.
lean-agent-method. How I put AI coding agents through a real ticket backlog without burning a month of plan in one night, plus the script that measures cost per change.
A cheaper model drafts every change. Scripts, not instructions, run the mechanical checks. A cheap critic reviews every change against six fixed questions, and the expensive model only sees what the critic cannot close. At most four changes in flight.
That took me from roughly 66 dollars of model use per change to about 25, with no drop in what got caught. Those are my numbers, at list prices, on one .NET codebase, so treat them as a shape rather than a benchmark. The method and the measuring script are both in the repo.
30 public repositories under @BaryoDev. Each solves one problem, ships to a package registry, and is tested rather than described.
| Project | |
|---|---|
| Verdict | Result pattern with a zero-allocation core, eight packages. The allocation promise is the product, so it is enforced by benchmark rather than asserted in a README: 0 B and 0 collections measured over 1.6M operations on 8 threads. |
| Mapsicle | Object mapping, thirteen packages at 2.2.0, one test project per integration. Benchmarked on x64 and arm64 against AutoMapper and Mapperly, and the published numbers say where it loses as well as where it wins. |
| Carom | Resilience: retry, timeout, circuit breaker, bulkhead, rate limiting, fallback, hedging. Zero dependencies in the core, netstandard2.0 upward, seven packages, 503 tests run against both .NET 8 and .NET 10. |
| Talaan | Spreadsheet and CSV reader, xlsx and CSV, zero dependencies. barakoCMS consumes it as a published package rather than a project reference, so the packaging is exercised for real. |
| Project | |
|---|---|
| umbraco-pwa | Turns an Umbraco site into an installable, offline-capable app. On the Umbraco Marketplace, 0.5.0 on NuGet. |
| umbraco-read-aloud | Read-aloud for an Umbraco site using Microsoft Edge neural TTS. |
| Project | |
|---|---|
| rnxjs | Reactive UI framework. Bootstrap-native, no build step. Suite green on every pull request after four URL-sanitisation fixes and a CI gate that could not fail before. Worked examples. |
| Kapehan | 42 hand-drawn coffee icons, MIT, plus a token-driven component sheet. The full-colour and currentColor mono builds come from the same geometry rather than being drawn twice. The CSS styles 34 component families against a 30-component manifest, and npm test asserts both counts and fails if either side gains an orphan. Browse the set. |
| rnxORM | Node.js ORM, integration-tested against PostgreSQL, SQL Server and MariaDB rather than mocked. |
| pwa-kit | Install prompt for Android and iOS, a network-first service worker, and the helpers around them. |
| read-aloud | Read-aloud for any site. Headless controller, web component, word highlighting. |
| feed-slurp | RSS and Atom fetching in the browser. |
| dopaminejs | Game feel engine: juice, rewards and feedback for HTML5 games. Built with it. |
| BaryoDev.Libraries.JavaScript | Zero-dependency TypeScript utilities on npm. |
| Project | |
|---|---|
| BaryoVM | PaaS-style deploys onto your own cheap VMs. Agentless, over SSH, one binary. Every BaryoDev deploy goes through it, which is how its gaps get found. |
| Baryo.CLI | Local AI chat on Docker Model Runner. Models run on your machine, no API keys, nothing leaves the laptop. |
Mostly postmortems of my own mistakes, and decisions with the reasoning attached.
| My benchmark said my library was 2x faster. It was not. | A performance gate that could not have failed for its own reason, and what it took to make it resolve what it reports |
| We built a modular CMS and deliberately did not make the modules plugins | Runtime assembly loading forecloses Native AOT permanently, and a plugins folder is a place where writing a file runs code |
| Your ORM is reading your lambdas with a regex | What lambda-parsing query builders actually do, and where that breaks |
| Migrating from Polly to Carom | The Polly maintenance fee is reasonable, the mechanism is the problem, and here is a pattern-by-pattern migration |
| Mapsicle 2.1: honest numbers against AutoMapper | Two architectures, medians of repeated runs, and a section on where it loses |
| The tenant filter that only worked on the way in | A multi-tenant event-sourcing bug that reads correctly and leaks on the way out |
| One cheap VM, nineteen containers, no platform | What running everything on one box costs, and what it saves |
| What two hundred issues taught us about building with AI | Where AI-assisted work fails quietly, and which gates catch it |
More at baryodev.medium.com.
I sort decisions by how expensive they are to reverse. A storage engine, a tenancy model, a public contract and a licence are one-way doors: those get argued out in writing first, with the reasoning kept rather than just the outcome, so the next person can disagree with the argument instead of guessing at it. Most other things are cheaper to try than to debate. That is why barakoCMS 4.0 shipped one-way doors only and everything else waited for 5.0.
Tests that cannot fail are the defect I look for first: a mock returning what the real dependency never returns, an assertion satisfied by a type's default value, a benchmark that prints and exits zero. Before trusting a gate I break the thing it guards and check it goes red.
AI-assisted daily, held to the same gates as everything else. The failure mode I design against is a green suite that proves nothing, which is why the mechanical checks are scripts and every change gets a critic before it gets an expensive model.
Languages C#, TypeScript, JavaScript, Go, SQL Architecture Event sourcing and projections, multi-tenancy (conjoined and database-per-tenant), modular monoliths over plugin runtimes, API contracts and versioning, licensing and one-way-door calls Backend .NET 8 to 10, ASP.NET Core, REST and GraphQL, microservices, CQRS-influenced design Messaging RabbitMQ, SQS, SNS, webhooks, background jobs Data PostgreSQL, SQL Server, Marten, Redis Cloud AWS (CDK, ECS, Fargate), Azure (Functions, App Services, DevOps), Oracle Cloud, Docker Testing xUnit, NUnit, Moq, Testcontainers, Playwright, Vitest, BenchmarkDotNet, security scanning in CI
📫 arnelirobles@gmail.com · 🌐 baryo.dev · ✍️ baryodev.medium.com



