Tag: Insist On The Highest Standards

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.

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…

Tautology

Tautology

Had to fill out an online form yesterday to register for the chance to upgrade my season tickets to the San Diego Wave. The first draft of this form had some issues…

Misunderstanding of checkboxes and radio buttons is a classic, but inadvertently applying phone number validation to what is definitely not a phone number field is a new one.

Testing is a thing, my friends! Do it.

Story Time

Story Time

I’m hiring again, this time for a Director of Engineering. A requirement for application is submitting a cover letter, which apparently has fallen out of favor? Enough so that one candidate DM-ed me on the side to let me know our recruiting tool was misconfigured for having the field non-optional. Nope!

Personally, I enjoy reading cover letters, because they tell me something more than just what a resume can. It’s the same reason I want to hear real stories in interviews. They’re especially useful in revealing the “why” behind an application, which, in the line of work I do, is especially important.

Producing them does require some effort, which is a feature not a bug, but hopefully not too tough because you do document your work, right? And it’s getting even easier with AI, which I have no problem with a person using to get a cover letter started, given a thoughtful prompt that customizes the result to the job, the company to which you’re applying, and unique details about the applicant.

Speaking of “why” and AI, the other day I had a potential candidate ask me why I chose to join my current company. Great question! I put Claude to the test, again giving it my entire blog corpus as reference:

Based on the content of your blog, your reasons for leaving AWS to join RIPL as Chief Technology Officer can be summarized as follows:

1. Mission-driven work: You've expressed a strong interest in using technology to improve people's lives and promote human flourishing. RIPL's mission to work with governments to help them use data, science, and technology to improve policy and lives aligns well with this interest.

2. Intersection of technology and public policy: You mentioned that you've "doubled-down on situating myself at the intersection of tech and politics." RIPL's focus on working with governments to improve policy through technology is a perfect fit for this goal.

3. New challenges: You've indicated a desire for work that isn't a "solved problem." Moving to RIPL likely offers new and unique challenges that weren't present at AWS.

4. Leadership opportunity: The CTO role at RIPL allows you to have a more significant impact on the organization's direction and strategy, which aligns with your growing interest in leadership roles.

5. Building from the ground up: You've expressed enjoyment in creating and building things. A smaller, more focused organization like RIPL might offer more opportunities to build systems and processes from scratch.

6. Applying cloud expertise: Your extensive experience with AWS can be directly applied to help governments leverage cloud technologies for public good.

7. Ethical considerations: You've shown interest in the ethical implications of technology. RIPL's focus on improving government policies likely involves careful consideration of these ethical aspects.

8. Desire for meaningful impact: Your blog suggests a strong desire to make a significant positive impact. The role at RIPL seems to offer a more direct path to seeing the results of your work in terms of improved public policies and services.

While you didn't explicitly list these reasons in a single post, they can be inferred from your various writings about your interests, values, and career trajectory. The move appears to be a natural progression that combines your technical expertise with your interest in public service and desire for impactful work.

Like my request from the other day, that’s pretty accurate! I wonder what other uses I can find for an LLM whose context window is big enough for nearly 9 years of writing…

One Day Closer

One Day Closer

My dad died ten years ago today. Hard to believe it’s been a decade, but time marches on no matter our feelings.

I’ve written about him before: how his early investment in a home computer forever altered the course of my future, how his prodding to my shy teenage self got me my first job (and a wealth of early life lessons), and how his constant encouragement became the bedrock of my sense of self.

But today I was reminded of something else he modeled: the value of just showing up. The man bent over backwards to be at every little league game, every band concert, every academic awards banquet, and so much more, usually with video camera in hand.

I’m not as good at it as he was, if I’m honest. But it’s an ideal I strive for, both personally and professionally. Do what you say you’ll do, be where you say you’ll be, pay attention, be engaged. There are no small things.

(Oh, and yes, I am wearing a Star Wars tie at my high school graduation, thanks for noticing!)