## The .frm File on a Shelf

In 1999, I opened Visual Basic 6 and built a desktop calculator called Project for Electronics. It solved Ohm's Law and Watts Law — enter any two of voltage, current, resistance, or power, and the program computed the other two. It worked. It was useful. Then it sat on a floppy disk for a quarter century.

I recently found the source — a single `Main.frm` file, 13 KB, packed with every classic VB6 antipattern you'd expect from that era. `Long` integers for electrical values. A `For` loop brute-forcing square roots. A 1 ms `Timer` control polling text boxes because VB6 had no event-driven input binding. `GoTo` labels scattered like confetti. It was beautiful in the way that a 1970s muscle car is beautiful: wrong in every measurable sense, but you have to respect the intent.

This is the story of porting that program to Rust, fixing every bug, expanding it from one calculator to six, adding a headless daemon mode, and then putting the whole thing under AGPL-3.0 — partly for principle, mostly for the joke.

## What Was Wrong (Everything)

Before writing a single line of Rust, I catalogued every defect in the VB6 source. Some were bugs; others were architectural decisions that made sense in 1999 but are radioactive today.

VB6 (1999)

`Long` (16-bit int) for watts, volts, amps, ohms — overflows above 32,767

Brute-force `For` loop to approximate square roots

1 ms `Timer` control polling all text boxes

No input validation (negative resistance accepted silently)

`GoTo Calculate`, `GoTo ClearFields` for flow control

`Format(Value, "0.00")` — fixed 2 decimal places always

Ohm symbol displayed as "Ohms" (no Unicode)

Rust (2026)

`f64` throughout — 64-bit double precision, no overflow

`(x).max(0.0).sqrt()` — one call, hardware-accurate

iced's reactive `update()` — recalculate only on change

Negative power/resistance rejected with error output

Structured `match` with priority-ordered pair matching

5-decimal precision with trailing-zero trimming via `trim_f()`

Proper Unicode Ω everywhere

## The Six Calculators

What started as a single Ohm's Law tool grew into a suite I'm calling MCP-Relational-Data that bridges two worlds: electronics engineering and modern business/AI economics. The GUI presents all six calculators in a two-column layout.

Calculator | Domain | Inputs
--- | --- | ---
Ohm's Law & Watts Law | Electronics | Any 2 of P, I, R, V
Margin & Markup | Ecommerce | Cost, Selling Price
ROI | Business | Investment, Revenue
AI Token Cost | LLM Economics | Model, Input/Output Tokens
Electricity Cost | Infrastructure | Watts, Hours, Days, Rate
Break-Even | Business | Fixed Costs, Price, Variable Cost

The Ohm's Law solver uses priority-ordered pair matching — it tries all six valid input combinations (I+R, I+V, I+P, R+V, V+P, P+R) in a specific order and computes all four values from whichever two are non-zero. The AI Token Cost estimator cycles through six models (GPT-4o, GPT-4, GPT-3.5 Turbo, Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku) with per-million-token pricing built into the source.

## Architecture: calc.rs Is the Soul

The most important design decision was separating pure calculation logic from every presentation layer. `calc.rs` contains zero I/O, zero GUI imports, zero serde. It's just functions: numbers in, numbers out. Both the iced GUI and the JSON daemon call these same functions.

    // calc.rs — the entire Ohm's Law solver
    pub fn ohm_calculate(p: f64, i: f64, r: f64, v: f64) -> (f64, f64, f64, f64) {
        if i != 0.0 && r != 0.0 { return (i * i * r, i, r, i * r); }
        if i != 0.0 && v != 0.0 { return (i * v, i, v / i, v); }
        if i != 0.0 && p != 0.0 { let v = p / i; return (p, i, v / i, v); }
        if r != 0.0 && v != 0.0 { let i = v / r; return (i * v, i, r, v); }
        if v != 0.0 && p != 0.0 { let i = p / v; return (p, i, v * v / p, v); }
        if p != 0.0 && r != 0.0 {
            let i = (p / r).max(0.0).sqrt();
            let v = (p * r).max(0.0).sqrt();
            return (p, i, r, v);
        }
        (p, i, r, v)
    }

The file structure mirrors this separation:

    src/
      main.rs    — CLI flag parsing, feature-gated dispatch
      calc.rs    — Pure functions (no dependencies)
      gui.rs     — iced 0.12 desktop app (behind #[cfg(feature = "gui")])
      daemon.rs  — stdin/stdout JSON API (behind #[cfg(feature = "daemon")])

## The Daemon: JSON Over Stdout

The original VB6 program could only be used by a human sitting at a Windows PC. The daemon mode changes that entirely. It reads one JSON object per line from stdin and writes one JSON object per line to stdout. Status messages go to stderr so they never pollute the pipe.

    $ echo '{"tool":"ohm","current":2,"resistance":4}' | mcp-relational-data --daemon
    {"tool":"ohm","power":"16 Watts(W)","current":"2 Amps(A)",
     "resistance":"4 Ohms(\u03A9)","voltage":"8 Volts(V)"}

This makes it trivial to call from Python, Node.js, shell scripts, or any MCP-compatible server wrapper. You can even build a slim daemon-only binary that skips the iced GUI dependency entirely:

    cargo build --release --no-default-features --features daemon

The protocol supports three operations: `list` (enumerate tools), `help` (get parameter docs for a tool), and any calculator name with its required parameters. Invalid JSON or unknown tools return structured error objects — no panics, no crashes.

## The iced 0.12 Adventure

Using iced 0.12 was its own challenge. The version available had some API gaps compared to the documentation — no `Container::border()`, no `container::Style` or `container::Status` types, no `rule::horizontal()`. Every border, separator, and styled container I tried to add failed to compile.

The solution was brutal minimalism: stick to only the APIs confirmed to work (`container`, `column`, `row`, `text`, `text_input`, `button`, `scrollable`) and use spacing and padding to create visual separation. It ended up looking cleaner than bordered panels would have anyway.

There was also a subtle lifetime error: using `&String::new()` as a static reference for the break-even calculator's empty output field caused a dangling reference at compile time. The fix was trivial — use `""` (a `&'static str`) instead — but tracking it down took a few rounds of compiler error archaeology.

## Why AGPL?

> "If you host this as a network service and modify it, you owe the world the source. Consider it a 25-year-later laugh at the VB6 original that was locked in a `.frm` file on a floppy disk."

The original program was proprietary by default — not because I made a deliberate licensing choice, but because that's what VB6 projects were. One file, one IDE, one OS. You couldn't build on it, extend it, or integrate it into anything else.

AGPL-3.0 is the opposite extreme. If you fork this calculator, wrap it in a web service, and charge people to use it, you must publish your modified source. It's a deliberately ironic choice for a program whose original incarnation was the least open thing possible: a compiled binary I distributed on a physical disk in 1999.

Practically, it doesn't matter. This is a calculator. Nobody is going to build a SaaS around Ohm's Law. But the license file is 662 lines long and it's there, and that's the point.

## What's in the Box

The final deliverable is a clean Rust project with everything you need to build, run, and extend it:

- `Cargo.toml` — feature-gated dependencies (gui + daemon default, either can be disabled)
- `src/main.rs` — CLI entry point with `--daemon`, `--help`, `--version`
- `src/calc.rs` — six pure calculation engines + AI model pricing data
- `src/gui.rs` — iced 0.12 desktop app, two-column layout, reactive updates
- `src/daemon.rs` — stdin/stdout JSON protocol, MCP-friendly
- `README.md` — full documentation with protocol reference, pair-matching table, VB6 bug list
- `QUICKSTART.md` — zero-to-running in 7 steps with Python, shell, and Node.js examples
- `LICENSE` — the full GNU AGPL-3.0 text, all 662 lines of it

## Try It

    git clone https://git.dcos.net/dcosnet/MCP-Relational-Data.git
    cd MCP-Relational-Data
    cargo run                          # GUI mode
    echo '{"tool":"ohm","voltage":12,"resistance":4}' | cargo run -- --daemon

A 1999 VB6 calculator I wrote as a teenager, now a modern Rust application with a desktop GUI, a headless JSON daemon, six calculators, and the most aggressively copyleft license I could find. The floppy disk would be proud.