Developer utilities you can paste secrets into 🙈
41 small Tools for JSON, JWTs, hashes, regex, diffs, cron and more.
They run in your browser, and the page is not allowed to send anything out.
Open blutils · Desktop app · Tools · How it works · Contributing
The real app, built with pnpm build and driven headless over the Chrome DevTools Protocol.
Every frame is a screenshot of a live page.
Most online formatters and decoders run on someone's server, or load a page full of ads and trackers next to the token you just pasted. blutils runs every Tool in the page, and the page's security policy blocks it from opening any connection at all.
| What it takes | How many |
|---|---|
| Servers that see your input | 0 |
Connections a page can open (connect-src 'none') |
0 |
| Accounts, cookies or sign-ins | 0 |
| Analytics, telemetry or ads | 0 |
| Registry files to edit when adding a Tool | 0 |
| Script before the first Tool loads, gzipped | 59 KB |
The desktop app makes one kind of request: it asks this project's GitHub releases for updates.
- Every Tool is one keystroke away. ⌘K or
/opens a fuzzy palette over all 41 Tools and the app's commands. - Live output. Type, paste or load a sample, and the output updates as you type. No run button.
- Chain mode. Pipe one input through a list of steps, such as base64 encode and then SHA-256, picked from 28 ops. Each step shows its output, and the chain stops at the first error.
- Smart hints. Opening the palette can read the clipboard and offer the right Tool, such as the JWT Decoder for a token. Off with one switch.
- Pins and tabs. Pin Tools to the top of the sidebar and jump to the first nine with
g 1tog 9. Turn on tabs to keep several Tools open at once. - A real URL for every Tool. Each one is a prerendered page, so it opens with content before any script runs, and back and forward work.
- Your input stays in the tab. It lives in
sessionStorageand is gone when the tab closes. Remember inputs keeps it across sessions, and Clear all data wipes everything. - Dark and light themes, and two densities.
| Category | Tools |
|---|---|
| format | JSON Format, JSON to Types, Format Converter (JSON · YAML · TOML · CSV), Dotenv / JSON, Markdown |
| encode | Base64, Base32 / Base58, Base Converter, Hex Viewer, HTML Entities, URL Encode, ROT13 / Caesar, JWT Signer |
| hash | Hash Generator, HMAC |
| text | Text Diff, Case Converter, Line Tools, Slugify, Text Statistics |
| time | Unix Time, Cron Parser, Timezone |
| generate | UUID, ULID, Password, Random String, QR Code, Lorem Ipsum |
| inspect | JWT Decoder, JSON Tree, JSON Diff, Regex Tester, URL Parser, Subnet Calculator, Chmod Calculator, Color Converter, Contrast Checker, Unicode Inspector, Hash Identifier, HTTP Status |
![]() |
![]() |
![]() |
![]() |
| Keys | Does |
|---|---|
⌘K or / |
Open the command palette |
| ↑ ↓, Return | Move through results, open one |
g then 1–9 |
Jump to a pinned Tool |
? |
Show every shortcut |
| Esc | Close the palette, a panel or the menu |
On Windows and Linux, ⌘ is Ctrl.
Open utils.blutarche.dev. Nothing to install.
The app is ad-hoc signed, not notarized, so a browser download triggers macOS Gatekeeper's "Apple could not verify" prompt. Install from the command line instead. curl and tar don't set the quarantine flag, so it opens with no prompt:
curl -L https://github.com/blutarche/blutils/releases/latest/download/blutils_aarch64.app.tar.gz | tar xz -C /Applications
open /Applications/blutils.appIf you already downloaded the .dmg in a browser, drag it to /Applications, then clear the flag:
xattr -dr com.apple.quarantine /Applications/blutils.appAfter the first launch it updates itself from signed GitHub releases, with no prompt.
Node 20+ and pnpm 10.
pnpm install
pnpm dev # dev server at localhost:5173
pnpm build # production build + prerender into dist/
pnpm preview # serve dist/ at localhost:4173
pnpm test # unit tests (Vitest)
pnpm typecheck # tsc --noEmit
pnpm tauri:build # the desktop app (needs Rust)Each Tool is a folder. The build finds every folder with import.meta.glob, checks that ids and slugs are unique, and wires the component in lazily, so only the Tool you open is downloaded. The same glob mechanism collects clipboard detectors and chain ops from optional files in each folder.
pnpm build renders every Tool URL to HTML with preact-render-to-string, and the client hydrates that markup. There is no server process at runtime. The site is static files on Cloudflare Pages, and the desktop app is the same client bundle inside a Tauri window.
Issues and pull requests are welcome.
Each Tool lives in its own folder under src/tools/<category>-<slug>/:
src/tools/format-json/
manifest.ts # eager — id, name, category, slug, icon, tags, seo
Tool.tsx # lazy — the actual UI component
detect.ts # optional — clipboard Detector
ops.ts # optional — Chain Mode Ops
Tool.test.ts # algorithm tests (no DOM required)
The glob registry in src/tools/_registry.ts discovers the folder automatically. Nothing else needs to change.
PR checklist
-
manifest.tsexports a validToolManifestwith a uniqueidandslug -
categoryexists insrc/categories.ts -
iconis a validlucide-preactexport (checked at build time) -
Tool.tsxusesuseToolInputfor any persisted input - Algorithm logic has
Tool.test.tscoverage against known vectors -
pnpm typecheck,pnpm testandpnpm buildpass
| Term | Meaning |
|---|---|
| Tool | A single utility (JSON formatter, base64 codec, …). Never "utility" or "plugin". |
| Chain | The sequential Op pipeline (⌘ chain mode). Never "pipe". |
| Chrome | Sidebar + Status Bar — the persistent shell surfaces. |
| Workspace | The main content area: Header, content region, and Tab strip. |
Preact 10 with preact/compat gives a React-compatible API at ~3 KB. The app has no server component needs and no React-ecosystem dependencies that couldn't be replaced, so Preact's size advantage over React is a clean win for a cold-load-sensitive utility app.
The demo and screenshots are the real app, not mockups. To redo them after a UI change, build, serve dist/ with pnpm preview, drive the pages headless with .claude/skills/run-blutils/driver.mjs (one --shot per frame), and join the frames with ffmpeg.
MIT. Copyright (c) 2026 Aikdanai Sidhikosol.



