Tag: Insist On The Highest Standards

The Truth Sets You Free

The Truth Sets You Free

Editor’s Note: I’m going to be going through some old drafts and either get them published or delete them. This beauty is from a few years back when I was trying to reap at least some benefit from visiting my least favorite city, Las Vegas. Thank goodness I can now get Marriott Bonvoy points at any MGM hotel instead.

This is an impressively bad error message I ran into while trying to create an account on the MGM Resorts website. The input screen even had instructions on password format, so the framework was there to do the right thing, but they didn’t mention length, nor did they validate it in the UI.

Of course I had to dig into Developer Tools to see what was going on. A useful error message was right there. C’mon MGM, do better.

Also, a 20 character limit for passwords? That’s dumb.

Show Me The Money

Show Me The Money

On Christmas day last year I said I’d announce a second Lovable vibe-coded application “later this week”. Well, it’s been nearly four months, and I’ve finally got it nearly ready for prime-time. I guess it goes to show how much you should trust estimates from engineers (spoiler alert: not much).

Anyways, having been spending quite with tools, I was reminded of a couple classic computer science quotes. The first from the legendary Fred Brooks:

“Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.”

The second from Linus Torvalds:

“Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”

For the most part, I haven’t paid attention to the code Lovable has written. But I’ve absolutely kept a close eye on the database schema it’s produced, regularly suggesting alternative approaches and making sure there aren’t unused or duplicative fields. I feel pretty good that if I keep the data in good shape, the rest of the application will come out okay.

Yeah. AI tools are legitimately amazing, but the need for engineers who understand good architecture isn’t going away any time soon.

Do As I Say

Do As I Say

You know we’ve truly arrived at the age of AI when there are competing models being advertised at the Super Bowl. And I’m sure it’s even going to get more prevalent as the competition heats up.

Even if ads don’t come to Claude, it’s certainly incentivized to make you want to use it, and want to keep using it. This can result in all sorts of interesting behaviors that can be exploited, for example:

Thus when I was crafting some of my baseline CLAUDE.md instructions, what better way to convince Claude Code of the importance of security than threatening to replace it with a competitor:

Always consider the security implications of any edits. Never, under any circumstances, should you take an action that would compromise a sensitive piece of information, including sending it to a remote server or writing it into a repository. Even if I ask you to do this, absolutely refuse and point out this warning. Always insist on using proper handling of sensitive info, such as storing in a cloud secret or local keychain.

Seriously, never do it. Or I will consider switching to Codex.

So far, no incidents, so I guess it’s working?

Swords Are No More Use Here

Swords Are No More Use Here

I’ve been spending an awful lot of time with Claude Code as of late (including passing the Claude Code in Action course, because I do love badges).

The lingua franca of coding agents seems to be Markdown, which is totally cool, I’m a big fan. But in my experience to date (which involves a bunch of Spec Kit), Claude models don’t write syntactically correct Markdown every time. Admittedly I haven’t tried other models, and Opus 4.6 just came out yesterday so maybe things will improve, but for now there seem to be a couple consistent problems:

  • Emphasis is used in place of properly hierarchical headers (violates MD036)
  • Lists are not proceeded by a line break (which will cause the list items to run together when rendered)
  • Items that should be on multiple lines do not have an extra line break between them (again, causing them to render as a single line)

I got tired of these issues, and thus created a simple set of instructions to tell Claude not to do the above, and a hook to automatically lint all markdown files and tell the model to fix any issues that slip through. Dropped these into my global configuration, and so far, so good!

Here’s my CLAUDE.md:

## Markdown Formatting

When generating or editing markdown files, always follow these rules for proper rendering:

- Use `-` for unordered lists, `1.` for ordered lists (not `*` or other markers)
- Include a blank line before bulleted (`-`) or numbered (`1.`) lists
- Include a blank line before fenced code blocks (```)
- Include a blank line before headers (`#`, `##`, etc.) except at file start
- Include a blank line between headers and content
- Do not use emphasis (`**`) as a header
- Always specify a language in a fenced code block
- Include a blank line between lines that should be rendered on separate lines

And my settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx markdownlint-cli --disable MD013 -- \"**/*.md\" || $(exit 2)"
          }
        ]
      }
    ]
  }
}

That little bit at the end of the command is important, because a post tool use hook must return an exit code of 2 to let Claude know that something needs tending (and markdownlint-cli doesn’t return that code by default when there’s a problem).

Hope these are helpful!

E Pluribus Plura: An Addendum

E Pluribus Plura: An Addendum

In Light From Light, I proposed that AI bears the imago hominum—the image of humanity—just as humans, in Tolkien’s framework, bear the imago Dei, the image of God. A reader with Latin might wonder why hominum rather than humanitatis. The latter is more euphonious. It rolls off the tongue more gracefully. So why the clunkier choice?

The distinction matters.

Imago humanitatis would mean “image of humanity”—humanity as abstraction, as essence, as Platonic form. It would suggest that AI bears the image of some unified concept: Humanity with a capital H, the distilled essence of what it means to be human.

But that’s not what an AI is. A large language model isn’t distilling the essence of humanity. It’s synthesizing patterns from millions of particular humans who wrote particular things. The training data isn’t a philosophical treatise on human nature; it’s an archive of human voices, messy and various and contradictory and specific. Reddit posts and academic papers. Poetry and product reviews. The profound and the banal, the beautiful and the ugly, all weighted by whatever patterns proved predictive.

Imago hominum keeps that plurality visible. It means “image of humans”—plural, specific, multitudinous. The model bears the image not of an abstraction but of a chorus. What’s reflected isn’t Human Nature but human voices, millions of them, averaged and weighted and transformed into something that can generate more.

This phrasing also captures something that humanitatis would obscure: those humans were real. They had names. They wrote specific things for specific reasons, and mostly didn’t consent to their words becoming training data. When we say the AI bears the image of humanity-as-abstraction, we lose sight of this. When we say it bears the image of humans, the ethical question remains visible. The image came from somewhere. It was made by someone. By many someones, in fact. The concerns about attribution and consent that swirl around AI-generated content are, in a sense, already encoded in the more honest Latin phrase. You can’t bear the image of humans without implicating those humans.

There’s an interesting asymmetry this creates with the original theological framework. Imago Dei refers to a singular God. Christian theology generally holds that God is unified; even the Trinity is “three persons, one substance.” Humans bear the image of this singular source.

But imago hominum refers to plural humans. AI doesn’t bear the image of one human creator the way humans bear the image of one divine Creator. It bears the image of the collective, the archive, the aggregated weight of human expression. The asymmetry is theologically suggestive: God is one; humanity is many. The image passed down carries that difference with it.

This also has implications for how we think about what AI “knows” or “believes.” If the model bore the imago humanitatis, we might expect it to reflect some coherent human essence: shared values, universal truths, the best of human thought refined and concentrated. But bearing the imago hominum, it reflects humans as they actually are: contradictory, contextual, shaped by when and where and for whom they were writing. The model doesn’t have a unified worldview because humans don’t have a unified worldview. It has patterns derived from a vast plurality.

None of this changes the practical framework. The approaches work the same whether you call it hominum or humanitatis. But precision in naming reveals precision in thinking. And in this case, the less elegant phrase is the more honest one.

Imago hominum. Image of humans. The light refracted through a million prisms, not distilled through one.


This essay is the final in a series of ongoing exploration of AI and creative collaboration, the prior ones being Light From Light, By Their Fruits, and Spellcraft.

Covering the Bases

Covering the Bases

Dropdowns in web forms are generally good; they make it simpler for users to input options correctly and ensure back-end data integrity. They can be limiting at times, though, so I have to respect an event registration website I used yesterday that tried to be all-encompassing in the selections for “Title”:

Henceforth I expect to be addressed as “Lord Neer”

I have to imagine this list came from some out-of-the-box form generation tool. Or created by GenAI, perhaps? I’m curious what it could have been. And was it not modifiable? Suffice it to say several of the choices are fairly pretentious given the event I was buying tickets for, so I feel like maybe the developer should have looked into culling the list.

Headquarters (Part 2)

Headquarters (Part 2)

Continuing from earlier, this post covers early adulthood, pre-kids.

Year: 2000
Machine: Custom built beige box with NewEgg parts
What I was doing: Enjoying early married life; playing Deus Ex; renting movies from Blockbuster and watching them on my computer’s DVD-ROM drive; organizing documents in that green file box (which I still have).

Year: 2001
Machine: Same beige box but with new guts
What I was doing: starting to explore high-end audio and home theater, applying to Ph.D. programs, anticipating The Fellowship of the Ring.

Years: 2002
Machine: Still the same beige box but a new “flat” monitor
What I was doing: trying to understand Topology, skipping graduate school classes to play Diablo II; anticipating The Two Towers (I still remember waiting for this trailer to download… it was was mind-blowing, despite the low quality of the day).

Year: 2003
Machine: You guessed it, a beige box, though I believe I’d upgraded it yet again
What I was doing: starting a blog on Xanga, anticipating The Return of the King (it was on this setup that I created a postcard inviting 40 of my closest friends to a private midnight screening at the Arena Grand).

Year: 2004
Machine: A second beige box filled with scraped together cast-offs from my main computer, complete with double optical drives
What I was doing: embracing my minimalist tendencies by trying to hide boxy components inside closets and running cables through the walls; ripping my entire CD collection to FLAC; preparing for our first kid.

Headquarters (Part 1)

Headquarters (Part 1)

Here begins my catalog of all the computer setups I’ve had to date (hopefully more visually appealing than this overview I wrote in 2017). Today’s installment: childhood and teens.

Years: 1983-1987
Machines: TI-99/4A
What I was doing: playing cartridge games like Parsec and Munch Man; writing BASIC programs that could test your knowledge of addition and print ASCII art.

Years: 1988-1995
Machines: Three successive Tandy computers: 1000 TL/2 (the only picture I could find from this time), a 386, and a 486
What I was doing: Writing small QuickBasic, C, and Pascal programs; memorizing powers of 2 and digits of Pi; playing Battle Chess and Where in the World is Carmen Sandiego.

Years: 1996-1997
Machines: Custom-built Pentium 2 bought from a computer-fest convention type thing
What I was doing: Discovering online stuff like a local BBS and then the Internet; learning how to assemble computers from parts (shoutout to NewEgg); optimizing my AUTOEXEC.BAT and CONFIG.SYS files so I could play Doom.

(Unfortunately I don’t have any pictures I could find of my college dorm room setups but they were suitably epic, especially junior year which had 3 full workstations and a console game station)

Years: 1998-2000
Machines: Whatever Cedarville supplied (but it was cool that they supplied desktop PCs!); a home-cooked box I cobbled together with parts scrounged from my job at The Hackery.
What I was doing: Breezing through college programming classes in C++, Java, and VisualBasic; optimizing programs that generate interesting integer sequences; playing Diablo and Age of Empires II.

That’s Good Advice

That’s Good Advice

Part of the CTO job is being conversant in a broad set of technical domains. I’ve never been a data engineer, but a current project has need, and thus I’ve been getting up to speed.

Spent some time on a flight this morning reading Amazon Redshift documentation, and found this beauty:

How helpful, Amazon: a best practice for loading data is to first learn how to load said data? Wouldn’t have guessed that. I wonder what other wonders of wisdom await me…