Blog · 20 Sep 2026
Why I built Formatloom: a small tool with a clear boundary
Why I built Formatloom as a privacy-focused JSON and YAML workbench, and the engineering decisions behind it.

Why Formatloom exists
Formatloom started with a small irritation: JSON and YAML are easy to read until a document needs checking, formatting, or conversion. The task itself is usually quick. The uncomfortable part comes when the document contains configuration or API data and the quickest online tool asks you to send it to someone else’s server. I wanted the document to stay in the browser.
Formatloom is the second small Mirtilo IO service after MaxBid. It is a free workbench for formatting and validating JSON, converting JSON and YAML, and explaining what may be lost during conversion. I kept the workflow narrow so I could take a real product through design, testing, deployment, and maintenance.
V1 gives me something to show, a chance to learn from use, and a way to see how the product behaves in search. It also lets me work through product boundaries, privacy, accessibility, deployment, and maintenance in a real free product. Saved workspaces, batch processing, an API, and team features are possible future additions. I want decisions about those features to follow demand rather than a guess made before launch.
The browser-local design
The browser-local requirement shaped the application. Formatloom has no account system, application database, saved workspace, upload endpoint, or processing API. Rails renders the application shell and the public entry pages. A TypeScript Web Worker handles the document in the browser. It checks the requested operation, recalculates the UTF-8 size, enforces the one MiB input limit, parses the document, and returns a bounded result with diagnostics or warnings.
The technical stack and its decisions
The application uses Ruby 3.4.6 and Rails 8.1 for the server-rendered shell, routes, page metadata, privacy copy, and health endpoint. Turbo handles navigation and Stimulus manages the page lifecycle. TypeScript, bundled with esbuild, owns the browser behavior and the worker protocol. Tailwind CSS 4 and Propshaft handle styling and assets. In production, a multi-stage Docker image runs Thruster and Puma as a non-root user. There is no database to configure, migrate, back up, or involve in document processing.
Each part of the stack has a practical reason. Rails keeps the shell and public pages in one application, so a separate frontend boundary is unnecessary. TypeScript puts the parser, worker messages, diagnostics, and analytics events under one type system. Moving the parser into a worker keeps it away from the main interface, which matters when someone opens a larger document on a slower device. The result is a small application that remains easy to follow while respecting the privacy rule.
Making structured-data conversion predictable
Local processing has to come with clear limits. Formatloom treats JSON as strict JSON, so it rejects comments, trailing commas, empty input, and malformed syntax. YAML is limited to one ordinary safe document. The converter warns about comments, anchors, aliases, duplicate keys, ordering, unsafe numbers, and parser warnings when those details may not survive a trip through JSON. Warnings still produce a usable result. Errors leave the original input available for correction.
That distinction matters because a formatting tool can change a document while appearing helpful. Formatloom makes the risk visible. Users can copy or download the result, and they see a warning when the source contains something the target format cannot represent faithfully.
Engineering quality in a small product
A shared Rails view powers the formatter, validator, and JSON/YAML routes. Stimulus manages the page lifecycle, Turbo handles navigation, and the worker stays independent from the DOM, storage, analytics, and network requests. Copy and download use browser APIs. Theme and language preferences are the only values that may remain in local storage. The same workbench supports English and Brazilian Portuguese, System, Light, and Dark themes, plus desktop, tablet, and mobile layouts.
Privacy is part of the interface as well as the code. The workbench explains that generated content stays local and that Formatloom does not save it. Optional Umami analytics records events such as a completed job, an error, a copy, or a download. Its allowlist contains operation and outcome metadata. It does not receive the input, the output, document names, content hashes, byte lengths, or session recordings. If the analytics service is blocked or unavailable, the workbench keeps working.
Accessibility and visual consistency were part of the initial requirements. Formatloom follows the Mirtilo IO and MaxBid visual language while keeping its own assets and deployment paths. The workbench has visible focus, labelled controls, live status messages, keyboard access, readable warning states, and a layout that works without a wide screen. These details affect whether someone can use the result comfortably and understand what happened.
Before calling the implementation finished, I wrote product specifications and contracts for the worker, the workbench, and analytics. The Rails controller accepts only known workbench modes. The worker validates its own operation and input size, returns bounded structured data, and ignores stale responses after a reset or navigation. User-derived messages are rendered as text. The content security policy restricts where scripts, connections, workers, and frames can go.
The test suite follows the same boundaries. TypeScript tests cover parser behavior, YAML fidelity warnings, worker validation, stale requests, analytics filtering, themes, and localization. Rails tests cover the route and privacy boundaries. System tests exercise the browser workflow, keyboard access, responsive layouts, reload behavior, branding, and network requests. CI also runs the asset builds, RuboCop, Brakeman, and Bundler Audit. It is a lot of checking for a small tool, but it makes future changes safer.
I used AI during parts of the implementation and while exploring technical choices. The product boundary came from writing down what Formatloom should never need to do. Once the no-upload and no-database rules were explicit, they shaped the architecture, worker contract, analytics contract, tests, content security policy, and release checklist. AI shortened some of the implementation work. Code review, testing, and inspecting the running product still mattered.
Deployment and hosting
The live service runs at formatloom.mirtilo.io on a VPS managed through Dokploy. The application is packaged as a production Docker image, and the browser assets are compiled during the image build. The image is published to GitHub Container Registry, then Dokploy deploys it behind an HTTPS proxy for the public domain. The container starts Thruster and Puma, runs as a non-root user, and exposes /up for health monitoring.
The repository also includes a Kamal deployment configuration for the same Docker and VPS shape. The live deployment uses Dokploy. The release setup has one application container, no application database, and no separate document-processing service. That keeps the operational cost in proportion to the product and leaves room to add infrastructure when users need it.
Impact and next steps
For someone using it, Formatloom is a quick way to inspect structured data without uploading it to a conversion service. For me, it is a live example of taking a small product from requirements through production. The work covers interface design, parser behavior, privacy, accessibility, testing, Docker packaging, deployment, analytics, and search discoverability. All of those concerns show up once the application is running.
Formatloom has changed how I think about the next Mirtilo IO product. JSON and YAML are the basis for one application with related workflows. JSON and CSV conversion and structured diff are possible next steps, with each one released and measured inside the same product. Formatloom will remain free. There will be no paid tiers or feature gates, so future additions will be judged by whether they make the product more useful.
One lesson has been that a deployed product still needs release evidence, production configuration, analytics checks, responsive verification, and documentation. A responding URL is only one checkpoint in the release.
Formatloom is free, and I measure completed jobs, errors, copies, downloads, return visits, and the value it adds to the Mirtilo IO portfolio. Those observations will help guide which improvements to build next instead of relying on a larger roadmap written in advance.