Ultraman: case study
A desktop app to test APIs with visible step pipelines that run the same in the window, the terminal, CI and AI agents.
Ultraman is a desktop tool for testing APIs with pipelines of visible steps: you chain requests, extract values from the responses, check the results, and run it all from a window, from the terminal or from an AI agent. It's built for developers and QA teams who today test by hand in Postman and then rewrite the same thing as scripts for CI.
Version 0.3.0 shipped on November 1, 2026, a week after the first commit: 262 commits, about 18,000 lines of code (TypeScript, React and Rust) and 801 tests. It runs on Windows, macOS and Linux and updates itself.
The problem
Testing a real API is almost never a single request: it's log in, keep the token, create something, read it back and check that the result is what you expected. Classic tools handle the individual request well, but the full flow ends up spread across collections, scripts and global variables nobody sees.
Ultraman starts from three ideas:
- The flow is the main object. A pipeline is a readable YAML file, versioned in git, that the window shows as a list and as a diagram.
- One definition for everything. The same pipeline runs in the window, in the terminal, in CI, under load and from an AI agent.
- Secrets don't leak. They're never stored in the project, never shown on screen again, and on disk they live encrypted behind a master password.
What it does
- Pipelines: request, extract, assert, repeat and parallel steps, plus reusable blocks. Run them whole or "up to here", with each step's status live and a run history.
- Request editor: method, params, headers, body (JSON, form, multipart, file), auth and options. Variables show as chips with their value on hover, with autocomplete and cURL import and export.
- Requests mode: a Postman-style area to send one-off requests, organized in collections that also live in git.
- Load tests: sustained, ramp and spike modes, up to 1,000 virtual users. Live charts, p50/p95/p99 and a verdict in plain language (holds, queues, rejects). It also flags responses that change when they shouldn't.
- CLI:
ultraman runfor the terminal and CI, with JSON output and exit codes. If the window is open, it shares the engine and history, and the run shows live in the window. - AI agents (MCP):
ultraman mcplets Claude or another agent read, save and run pipelines. A person approves every call in the window. - Git sync: a Sync button that commits and pushes only Ultraman's files, with a visual or YAML diff to resolve conflicts.
- Languages: English, Spanish and Portuguese, switchable on the fly.
Architecture and stack
Everything goes through serve, a local Node server that only listens on 127.0.0.1. The window, the terminal and the agents are all clients of the same engine, so they see the same runs and the same history.
- UI: React, TypeScript, Vite and CodeMirror.
- Desktop: Tauri 2 in Rust, for the system keychain, the updater and the server's lifecycle.
- Engine and server: Node 24 with TypeScript and no build step, YAML and Zod.
- HTTP: UltraTon, a hardened HTTP client for Node.
- Agents: Model Context Protocol, with the official SDK.
- Distribution: GitHub Actions, GitHub Pages and install scripts in bash and PowerShell.
Technical highlights
A secrets vault designed against local malware
The goal was that a malicious app scanning the disk for keys finds nothing useful. Before designing it, I compared how Postman, Insomnia, Yaak, Bruno and Hoppscotch solve it.
- A master password derives a key with scrypt (N=2^17), which wraps a random data key. Secrets are encrypted with AES-256-GCM.
- The vault locks after 30 minutes of inactivity and when the window closes. The unlocked key only lives in memory.
- "Remember on this machine" is opt-in and uses the system keychain. The checkbox warns that on Windows and Linux other apps can read it.
- The local server only opens the vault for the window: it requires a session token and the UI's origin. The token goes from process to process over stdout, never through the disk.
- In responses and in what was sent, secrets show up as
[secret:x].
Signed updates, end to end
- Every release publishes an RSA-signed
SHA256SUMS. The install scripts (bash and PowerShell) carry the public key and install nothing without a valid signature. - The app updates itself with Tauri's updater and minisign signatures. The order matters: download, verify the signature, let the server finish what it's running, install and restart. If the install fails, the server comes back up.
- It won't offer to update while there are unsaved changes or a run in progress, and it says why.
- The CLI refreshes itself from the app's own files, without downloading anything.
Distribution with no dependencies
The installer brings its own Node 24, verified against nodejs.org's checksums, so there's nothing else to install. A single command installs the app and the CLI, and there's a CLI-only mode for CI.
One engine per project
If the window is open, ultraman run doesn't run on its own: it hands the pipeline to the window's server. That way the terminal and the window share the engine and the history, and whatever you launch from the terminal shows up in the window while it runs.
Consent for AI agents
The MCP server can't approve itself: approving requires the session token and the window's origin, so an agent can't skip the person with a curl. Every agent request is logged.
Quality
- 801 tests in 83 files (about 10,000 lines), with
node:testand no extra frameworks. They cover the engine, the server, the CLI, the app and the distribution too: the install scripts run against a fake signed release, including forged signatures and tampered checksums. - Test-driven development: every new feature starts with a failing test.
- A security audit documented in the repo, with every finding and its fix.
- GitHub Actions are pinned by hash. CI only runs when a release is published, to save a private repo's minutes: tests first, then the Windows, macOS and Linux builds.
- The full auto-update flow was tested end to end on Windows (0.3.0 to 0.3.1), including a forged signature that gets rejected without leaving the app broken.
My role
A personal project end to end: idea, product design, visual identity, architecture, development, security, distribution and the landing page. I built it with Claude Code as a pair programmer. I defined the product, made the design and security decisions and reviewed every change before merging it.
Some decisions I made along the way:
- Every unsafe action warns about the risk and offers a safe path, instead of forbidding it.
- Everything the user creates lives in readable files inside their repo, not in a cloud account.
- I work in pull requests, one per feature, with a plan and a spec written before any code.
Links
- Website and install
- Releases and release notes
- UltraTon, the HTTP client it runs on