Rust

Weftan, a backup plan that became a Rust rabbit hole

Weftan started as a fun backup plan. If TALA died hard, could I still have the layout engine around in some usable form?

TALA arranges diagrams for D2. Recovering its behavior and rebuilding it in Rust seemed like an interesting thing to try. That eventually became Weftan, and then a larger work-in-progress project called d2-rs.

Weftan was faster than the Go version of TALA when that was an external proprietary binary. The slightly annoying part is that TALA built into D2 was faster still. So naturally I started thinking about rewriting more of the surrounding thing too.

Recovering the behavior

The early work used TALA release artifacts: symbols, debugging information, disassembly, and comparisons with the executable. Reconstructed Go code informed the Rust implementation. This was recovery work, and the provenance matters; I did not independently invent the same layout engine by looking at a few pictures.

Then TALA’s source became available in D2 v0.9.0. That changed the situation quite a bit. There was now an upstream source implementation to follow and compare against, instead of relying entirely on recovered behavior.

There is a lot hidden inside “put the boxes somewhere sensible.” Containers, labels, edge routes, and the order in which equally reasonable choices get considered can all affect the final result. Two diagrams can look basically the same while disagreeing on a lot of coordinates.

So the useful comparison was to give both implementations the same measured graph and seed, then compare the actual geometry. When something differed, there was a smaller question to investigate than “why is this picture weird?”

Matching a corpus

The recorded Weftan baseline reached exact matches on all 120 successful single-seed comparisons in the checked-in corpus. That included 2,964 boxes and 974 routes, along with their corresponding labels and node icons. One large-grid case hit the work limit in both engines and was recorded separately.

I was happy with that. I also want to keep the size of the claim attached to it: those are the cases in that corpus, with that reference version and comparison setup. It does not mean every possible D2 input will behave identically.

Being able to reproduce a mismatch is useful even before it is fixed. It gives the next round of work an actual target. Otherwise it is very easy to keep improving the appearance of one example without knowing whether another example got worse.

The comparison machinery ended up being a useful result of the experiment in its own right.

The plugin tax

Weftan plugs into D2 as an external layout process. D2 has to pass a graph across that boundary and get the result back. Built-in TALA does not pay that same process and protocol cost.

There are two different comparisons here. Against the old external proprietary Go TALA binary, Weftan was faster in my testing. Against TALA built into D2, the end-to-end measurements went the other way. The baseline changed, and that distinction matters.

Plugin overhead is a plausible explanation for at least some of the gap with built-in TALA, but I have not isolated it well enough to say it accounts for the entire difference. “Rust” on the box does not make the complete workflow faster by itself.

That leaves Weftan in a perfectly reasonable place as a fun experiment. The backup-plan motivation got me started, and I got a recovered engine, comparisons, and a much closer look at the behavior out of it.

It also left me curious about removing that boundary altogether.

Following upstream in Rust

The next rabbit hole is d2-rs: a pure-Rust implementation targeting native execution and WebAssembly, with the layout engines running in the same process. The TALA work from Weftan has moved into that effort.

I am interested in following upstream behavior and exploring parallel execution where it makes sense. Having the surrounding pipeline in Rust should also make it easier to investigate costs without the external plugin boundary sitting in the middle of every layout.

This is still under construction. There are working source-processing and rendering paths, but plenty of compatibility work remains. A working SVG example is a nice milestone; it does not establish that the renderer, all the diagram features, or the other engines are interchangeable with D2.

I also do not have a speedup to announce for the rewrite. That is something to measure as it develops.

For now, Weftan is public. It was a fun backup plan, it taught me things, and it apparently gave me another project to work on.

10:34 am / Rust , D2 , Reverse engineering , Wasm

codex-status-json

I made a small Rust CLI that prints Codex status as JSON.

The short version is that I wanted Codex conversations to know my account, model, and quota state without opening the interactive TUI and reading /status like a person.

This is mostly useful with Codex goals. I am on the Pro 20x plan, which is the $200/month tier, so sometimes I really do have quota to burn. If I can read the remaining quota first, I can make a goal with an actual target instead of guessing how ambitious I should be.

The missing command

Codex has /status in the interactive CLI. It shows useful stuff: account, model, context, writable roots, and rate limits.

That is fine when I am sitting in the TUI. It is less fine when I want another Codex conversation to ask the same question.

There is an upstream issue asking for this exact kind of thing: a non-interactive JSON/headless replacement for /status. The issue is still open as I write this. There is also codex doctor --json, which is useful, but that is a diagnostic report. It is not the same as “tell me my account/model/quota status right now.”

So I made codex-status-json.

The first version was worse

The first version did what you would expect from a tool born out of impatience: it opened Codex in a PTY, sent /status, waited for the panel to settle, captured the terminal output, stripped ANSI escapes, and parsed the text.

It worked. It was also clearly a bad long-term place to live.

Terminal scraping is annoying because every little UI change can break you. The parser has to care about box drawing, timing, update notices, trust prompts, terminal width, and whatever else the TUI happens to render that day.

Still, it was useful. It gave me JSON like this:

{
  "schema_version": 1,
  "account": {
    "email": "user@example.com",
    "plan": "Pro",
    "raw": "user@example.com (Pro)"
  },
  "model": {
    "name": "gpt-5.5",
    "details": "reasoning high",
    "raw": "gpt-5.5 (reasoning high)"
  },
  "buckets": [
    {
      "name": "default",
      "limits": [
        {
          "kind": "5h",
          "remaining_percent": 99,
          "resets": "14:44",
          "reset_at_unix": 1780350290
        },
        {
          "kind": "weekly",
          "remaining_percent": 70,
          "resets": "08:23 on 7 Jun",
          "reset_at_unix": 1780845815
        }
      ]
    }
  ]
}

That was enough to unblock the thing I wanted.

The less cursed version

A few days later, I switched the default backend to Codex’s app-server.

That is a much better source than scraping the TUI. The tool starts:

codex app-server --listen stdio://

Then it sends JSON-RPC calls for:

  • account/read
  • account/rateLimits/read
  • config/read

That gives it the same kind of account, model, and quota information without pretending a terminal status panel is an API.

Important caveat: Codex app-server is documented, but it is also described as experimental and may change. So this is still not a supported codex status --json. It is just a more sensible workaround than screen scraping.

The PTY backend is still there as a fallback:

codex-status-json --backend pty

But the default is now:

codex-status-json --backend app-server

This is a bridge

I do not expect this to be the forever answer.

Codex’s usage and billing surface is still moving. OpenAI has already introduced things like banked rate-limit resets, so the status shape is not just “two counters and call it done.” There are plans, windows, reset times, secondary buckets, and whatever else comes next.

So I can see why OpenAI might not want to commit to a stable status JSON contract yet. That is fine. I still wanted something local that worked now.

This is the same kind of bridge as a lot of these small tools: use the available pieces, make the annoying gap tolerable, and be happy if the official thing eventually replaces it.

The repo

The project is here:

https://github.com/nelsonjchen/codex-status-command

Install it locally with:

cargo install --path .

The README has the options and limitations. The tests include a captured /status fixture so the text parser can at least fail loudly when Codex changes its display.

I would still rather have an official codex status --json. Until then, this is small, local, and useful enough.

3:03 pm / Codex , Rust , CLI , JSON , Automation

Moving Gmail Send mail as to Cloudflare SMTP

I just finished moving my Gmail “Send mail as” setup completely to Cloudflare Email Service’s native SMTP submission. I can send out emails under my mindflakes.com domain.

The short version is that I had built a small Rust SMTP-to-Cloudflare REST API relay in April. Today I noticed Cloudflare had shipped native SMTP submission.

Part of the appeal here is minimizing vendors. Cloudflare already hosts the domain, handles incoming mail through Email Routing, and now can handle outgoing mail through Email Service too. For a personal domain, that can be cheap or free, and it is a nice alternative to paying for Google Workspace when a personal Gmail account is otherwise fine.

The April hack

In April, I saw Cloudflare’s public beta announcement for Email Service and got excited about using Cloudflare for both inbound and outbound personal-domain mail.

Then I got sad. I wanted Gmail to send mail for one of my domains through Cloudflare Email Service, but I did not see a native SMTP submission path I could just point Gmail at.

Gmail’s Send mail as feature wants a normal authenticated SMTP server. You give it a hostname, a port, a username, and a password. Gmail talks SMTP. It does not want to be handed a REST API endpoint.

[... 668 words]

2:13 pm / Rust , SMTP , Cloudflare , Gmail , Email

Blocking spammy caller names with VoIP.ms Call Hunting

I made a small Rust VoIP.ms CNAME blocker.

The short version is that I wanted to block a caller by name instead of by phone number.

This sounds like it should be an option in VoIP.ms. For all the features VoIP.ms has, this is not one of them. So I made one for cheap.

The missing filter

VoIP.ms has a pretty capable CallerID Filtering feature. You can filter on specific caller ID numbers, phone book groups, anonymous callers, calls that do not match the North American number format, STIR/SHAKEN attestation level, and wildcard patterns like area-code-ish blocks.

That is all useful, but these asshole spam callers and scammers do not politely stick to one number. They rotate numbers. Blocking one just means the next call comes from another one. What I wanted to block on was the caller ID name.

VoIP.ms has CNAM support too, but as far as I can tell it is for displaying names, not filtering on them. Their blog post on stopping spam calls talks about filtering numbers, area codes, and anonymous callers, while describing CNAM as a way to identify callers before picking up. The Caller ID wiki page describes incoming Caller ID name lookup as an optional per-DID setting that can display a caller name for US and Canadian callers.

[... 718 words]

7:30 pm / Voip , Sip , Rust , Voip ms , Telephony

GitHub Wiki SEE: Search Engine Enablement

I built this in March, but I figure I’ll write about this project better late than never. I supercharged it in June out of curiosity to see how it would perform. It’s just a ramble. I am not a good writer but I just wanted to write stuff down.

TLDR: I mirrored all of GitHub’s wiki with my own service to get the content on Google and other search engines.

If you’ve used a search engine to search up something that could appear on GitHub, you are using my service.

https://github-wiki-see.page/

Did you know that GitHub wikis aren’t search engine optimized? In fact, GitHub excluded their own wiki pages from the search results with their robots.txt. “robots.txt” is the mechanism that sites can use to indicate to search engines whether or not to index certain sections of the site. If you search on Google or Bing, you won’t find any results unless your search query terms are directly inside the URL.

The situation with search engines is currently this. For example, if you wanted to search for information relating to Nissan Leaf support of the openpilot self-driving car project in their wiki, you could search for “nissan leaf openpilot wiki”. Unfortunately, the search results would be empty and would contain no results. If you searched for “nissan openpilot wiki”, “https://github.com/commaai/openpilot/wiki/Nissan" would show up correctly because it has all the terms in it. The content of the GitHub wiki page is not used for returning good results.

[... 1,550 words]

6:12 pm / Github , Wiki , Seo , Rust , Cloud run , Bigquery , Gcp

GitHub Wiki SEE

https://github-wiki-see.page/

A project to get GitHub Wikis indexed by Google Search.

Explanation is right on the front page.

If a search engine can’t see it, it may as well be invisible.

Long-term project involving Rust, BigQuery, Cloudflare Workers, and lots of random hosting.

Probably one more the more visited sites on the internet and a continous effort to keep costs low.

Has caused GitHub to revisit their policy on a limited subset of Wikis meeting some criteria.

Will continue until all Wikis are indexed even if they are publically editable or don’t meet some star count criteria.

Personally, I just got really dismayed all this documentation I was doing on a Wiki wasn’t visible to Google. Then I realized it was a good idea to make it visible. Then I realized others don’t realize it was invisible at all. This was a problem.

12:00 am / Github , Wiki , Seo , Rust , Cloud run , Bigquery , Gcp , Flyio , Cloudflare