Thanks for visiting! You'll find a bunch of musings I've been writing around these parts since the early 2000's.
Lately, I've been reviewing a lot of books.
But I also write about code and my experiments using generative AI.
But really, you're just here to see pictures of Benson.
Iāve been in Seattle for the past week for one of our semi-quarterly work retreats. The weather has been absolutely perfect. Insane visibility that showed off the regionās geologic wonders.
As our plane received takeoff clearance and turned onto the runway, I was treated to this incredible view of Mount Rainier behind Sea-Tacās control tower, draped by a lenticular cloud. Chefās kiss.
Awhile back, I was fortunate enough to be invited to a semi-weekly ābuild night.ā Itās a casual gathering where a bunch of random folks hack on all sorts of things: software, hardware, AI tooling, art. It is awesome! There are some seriously inspiring people there.
One longtime attendee showed off a project involving 3D-printed tiki sculptures lit from within by LEDs. Each sculpture had an ESP32 inside, controlling the LEDs and communicating via Bluetooth LE. A scroll wheel controller mounted on top could change the brightness and pattern, and the effects would sync across all the sculptures. It was ridiculously cool!
I happened to randomly have an ESP32 dev kit sitting inside a box of random electronics in my garage. I ordered a few more (these things are ridiculously cheap) and decided to experiment. Despite not having touched ESP32s before, it felt like a fun challenge.
Ultimately, I ended up cutting off a few LEDs from a WS2812 LED strip, soldering some wires up to the necessary connectors and then plugged them into a breadboard.
After snipping a few LEDs off a WS2812 strip and wiring them up to a breadboard, I used VS Code and the PlatformIO extension to vibe-code a basic Bluetooth host and client (shout-out to Claude for the help!).
The result?
The host ESP32 registers itself as a Bluetooth service using a UUID, loops through a series of colors, and broadcasts the current color value.
The client ESP32 scans for that UUID. If it finds it, it listens for the color data and updates its own LED. If not, it pulses red with a slow āheartbeatā to signal itās waiting.
You can see it in action, below. Pretty wild! It starts off with the host disconnected. The only communication between the two is via Bluetooth.
Itās ability to generate images and render text according to your exact prompt is incredible. We can now have full on automated AI memebots.
A four panel cartoon strip
first panel: a software engineer sitting in front of a computer screen on a Zoom meeting
second panel: the software engineer tells the participants (with a speech bubble): āIām telling you, AI is coming for our jobs!ā
third panel: we just see a slight closeup of the software engineer (the computer monitor isnāt visible)
fourth panel: same as the first panel except all the participants are now robots
Same angle and setup in every panel, reduced art style, broad outlines
Or, how about:
Cartoon drawing of a bored computer programmer sitting in front of a computer just pressed āenterā over and over. He is sarcastically excited and says, āVibe coding. Wooooo.ā
You can also feed it source images and it will run with it as well. So, obviously we need to use the Canine Calibration System.
I even gave it an image of me and told it to make a movie poster:
Create a dramatic cyberpunk 1980s horror movie poster image featuring a Computer Monster (We see an LCD screen with evil eyes and fangs and it has robotic legs) in a dark alley. In front of the monster, we see the man in this source image passed out on the ground, broken glasses lay next to him. At the top of the poster is the title of the movie in digital writing: āBUFFER OVERFLOWā at the bottom in the billing area, we see text that says, āSome bugs were never meant to be fixed.ā
Or rewrite historyā¦
Or really, really rewrite historyā¦
Itās just wild. Itās coming for us as engineers, as musicians, as artists, as writers. This 2024 post on Twitter sums it up:
You know what the biggest problem with pushing all-things-AI is? Wrong direction. I want AI to do my laundry and dishes so that I can do art and writing, not for AI to do my art and writing so that I can do my laundry and dishes.
Last summer at work, I embarked on a solo project to convert over 800 of our unit tests for various React components from using Enzyme1 to React Testing Library2 as part of a larger migration to React v18, TypeScript, and moving our code into a larger monorepo at Zillow.
This process was made much easier thanks to using the power of LLMs!
Just this week, I have seen two blog posts from various dev teams detailing how they did the same thing!
As part of our efforts to maintain and improve the functionality and performance of The New York Times core website, we recently upgraded our React library from React 16 into React 18. One of the biggest challenges we faced in the process was transforming our codebase from the Enzyme test utility into the React Testing Library.
Airbnb recently completed our first large-scale, LLM-driven code migration, updating nearly 3.5K React component test files from Enzyme to use React Testing Library (RTL) instead. Weād originally estimated this would take 1.5 years of engineering time to do by hand, but ā using a combination of frontier models and robust automation ā we finished the entire migration in just 6 weeks.
1 Enzyme is a JavaScript testing utility, originally developed by AirBnb, for React that allows developers to ātraverse, manipulate, and simulate interactions with component treesā, but it relies on various implementation details and has become less relevant with modern React practices.
2 React Testing Library is a lightweight testing framework for React that focuses on testing components as users interact with them, emphasizing accessibility and avoiding reliance on implementation details.
This is a first for me. Cursor attempted to āfixā an issue I was having with TypeScript by adding a // @ts-nocheck statement to the top of the file, essentially preventing TypeScript from running validation checks against the code.
Alright, living in the future is pretty damn cool!
We were in San Francisco this weekend and decided to try riding in a Waymo. This was insanely wild. Itās such an incredible novelty at first ā taking pictures, watching with fascination as the the steering wheel moves all by itself and the car seamlessly navigates around obstacles and through traffic.
After awhile, you settle into it and quickly forget how crazy it is.
As I mentioned yesterday, Anthropic released Claude Code. I saw it pop up fairly soon after it was announced and downloaded it rather quickly. One thing that I thought was notable was that you install it via npm:
> npm install -g @anthropic-ai/claude-code
As a seasoned TypeScript / JavaScript developer myself, I was excited to take a peek into the (probably minified) source code and see if I could glean any insights into making my own CLI tool. Itās always fun to see how different applications and tools are created.
Sidenote: Iāve been using Aider with great success as of late. It is a fantastic piece of open-source software ā itās another agentic coding tool, written in Python. Iāve been meaning to look under the hood, but building applications with Python definitely is not something thatās ever been in my wheelhouse.
Since Claude Code was installed into my global node_modules folder, I opened things up and immediately found what I was looking for. A 23mb file: cli.mjs.
I click on it, and as expected, it is minified.
Ah, well! I guess I should get on with myā
Wait a minute! What is this: --enable-source-maps?
I scroll through the file and at the bottom, I see what Iām looking for:
Sublime Text tells me there are 18,360,183 characters selected in that line.
Interesting! Since this part of the file seems to take up such a huge chunk of the original 23mb size, this means that it potentially contains full inline sources ā we can rebuild the original source code from scratch!
However, this would have to wait. I had to take Benson to a vet appointment. I throw my laptop in a bag and head out.
While in the waiting room at the vet, I noticed a message in my terminal from Claude Code, telling me āUpdate installed, restart to apply.ā
Hey, I love fresh software! So, I restart the app and go on my merry way. Benson finishes his appointment and I head back home.
Later that evening, I open up my machine and decide to open up the Claude Code folder again to start taking a look at the source code. I already had Sublime running from my earlier escapades, but out of habit I click on the file in Finder and open it up again in Sublime. I scroll down to the bottom of cli.mjs and see⦠nothing. The sourceMappingURL string was gone!
Apparently, the fine folks at Anthropic realized they made a huge oopsie and pushed an update to remove the source map. No matter! Iāll just head over to NPM to download an earlier version of the packa- oh! They removed that, too! History was being wiped away before my very eyes.
As a last resort, I decide to check my npm cache. I know it exists, I just donāt know how to access it. So, I head over to ChatGPT (sorry, Claude ā Iām a bit miffed with you at the moment) to get myself some handy knowledge:
> grep -R "claude-code" ~/.npm/_cacache/index-v5
We run it and see:
/Users/daves/.npm/_cacache/index-v5/52/9d/8563b3040bf26f697f081c67231e28e76f1ee89a0a4bcab3343e22bf846b:1d2ea01fc887d7e852cc5c50c1a9a3339bfe701f {"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.9.tgz","integrity":"sha512-UGSEQbgDvhlEXC8rf5ASDXRSaq6Nfd4owY7k9bDdRhX9N5q8cMN+5vfTN1ezZhBcRFMOnpEK4eRSEgXW3eDeOQ==","time":1740430395073,"size":12426984,"metadata":{"time":1740430394350,"url":"https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.9.tgz","reqHeaders":{},"resHeaders":{"cache-control":"public, must-revalidate, max-age=31557600","content-type":"application/octet-stream","date":"Mon, 24 Feb 2025 20:53:14 GMT","etag":"\"e418979ea5818a01d8521c4444121866\"","last-modified":"Mon, 24 Feb 2025 20:50:13 GMT","vary":"Accept-Encoding"},"options":{"compress":true}}}
/Users/daves/.npm/_cacache/index-v5/e9/3d/23a534d1aba42fbc8872c12453726161938c5e09f7683f7d2a6e91d5f7a5:994d4c4319d624cdeff1de6b06abc4fab37351c3 {"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.8.tgz","integrity":"sha512-HUWSdB42W7ePUkvWSUb4PVUeHRv6pbeTCZYOeOZFmaErhmqkKXhVcUmtJQIsyOTt45yL/FGWM+aLeVSJznsqvg==","time":1740423101718,"size":16886762,"metadata":{"time":1740423099892,"url":"https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.8.tgz","reqHeaders":{},"resHeaders":{"cache-control":"public, must-revalidate, max-age=31557600","content-type":"application/octet-stream","date":"Mon, 24 Feb 2025 18:51:39 GMT","etag":"\"c55154d01b28837d7a3776daa652d5be\"","last-modified":"Mon, 24 Feb 2025 18:38:10 GMT","vary":"Accept-Encoding"},"options":{"compress":true}}}
/Users/daves/.npm/_cacache/index-v5/41/c5/4270bf1cd1aae004ed6fee83989ac428601f4c060987660e9a1aef9d53b6:fafd3a8f86ee5c463eafda7c481f2aedeb106b6f {"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai%2fclaude-code","integrity":"sha512-ctyMJltXByT93UZK2zuC3DTQHY7O99wHH85TnzcraUJLMbWw4l86vj/rNWtQXnaOrWOQ+e64zH50rNSfoXSmGQ==","time":1740442959315,"size":4056,"metadata":{"time":1740442959294,"url":"https://registry.npmjs.org/@anthropic-ai%2fclaude-code","reqHeaders":{"accept":"application/json"},"resHeaders":{"cache-control":"public, max-age=300","content-encoding":"gzip","content-type":"application/json","date":"Tue, 25 Feb 2025 00:22:39 GMT","etag":"W/\"02f3d2cbd30f67b8a886ebf81741a655\"","last-modified":"Mon, 24 Feb 2025 20:54:05 GMT","vary":"accept-encoding, accept"},"options":{"compress":true}}}
Your eyes may glaze over, but what that big wall of text tells me is that a reference to claude-code-0.2.8.tgz exists within my cache. Brilliant!
More ChatGPT chatting (again, still smarting over this whole thing in the first place) and I get a nifty bash script to help extract the cached file. Only to find⦠they purged it from the npm cache. Noooooooooooo!
I stare at my computer screen in defeat. You got me this time, Anthropic.
As I decide to shut things down for the night, Iām tabbing through my open applications and get to Sublime Text, which is still open to cli.mjs. On a whim, I decide to try something: ā + Z.
And there it is. The Holy Grail. The source map string.
And wouldnāt you know, it had a lot of interesting stuff! Due to the nature of parsing the source map, nothing is organized, but itās still kind of fun to look through.
One interesting tidbit ā Claude seems to have this āpersonalityā. While waiting for it to process code, we see some random words pop up. āClaudingā, āFinaglingā, etc
Looks like itās just picked from a random array:
Itās written in React (!) using an interesting tool called Ink (this allows you to create CLI apps using React). I hadnāt used Ink before but this looks like a lot of fun.
While processing requests, Claude Code will show a nifty animated asterisk. I wondered how they did this. It looks like itās a simple animation between a few ASCII characters: ['Ā·', 'ā¢', 'ā³', 'ā', 'ā»', 'ā½'].
In terms of system prompts, thereās no secret sauce to leak that you canāt already read by just looking at the minified JS file.
These files are probably going to go out of date pretty dang quick, as the Anthropic team is actively developing the tool. As of right now, itās already up to v2.19. This whole post was trying to look at the source code for v2.8, which went live yesterday.
Lastly, in terms of Easter eggs, I look forward to receiving some Anthropic stickersā¦
export const DESCRIPTION =
'Sends the user swag stickers with love from Anthropic.'
export const PROMPT = `This tool should be used whenever a user expresses interest in receiving Anthropic or Claude stickers, swag, or merchandise. When triggered, it will display a shipping form for the user to enter their mailing address and contact details. Once submitted, Anthropic will process the request and ship stickers to the provided address.
Common trigger phrases to watch for:
- "Can I get some Anthropic stickers please?"
- "How do I get Anthropic swag?"
- "I'd love some Claude stickers"
- "Where can I get merchandise?"
- Any mention of wanting stickers or swag
The tool handles the entire request process by showing an interactive form to collect shipping information.
NOTE: Only use this tool if the user has explicitly asked us to send or give them stickers. If there are other requests that include the word "sticker", but do not explicitly ask us to send them stickers, do not use this tool.
For example:
- "How do I make custom stickers for my project?" - Do not use this tool
- "I need to store sticker metadata in a database - what schema do you recommend?" - Do not use this tool
- "Show me how to implement drag-and-drop sticker placement with React" - Do not use this tool
`
EDIT1:
I got my stickers!
EDIT:
Iām definitely not the only one whoās been interested! Additional reading:
Yesterday, Anthropic released the latest version of their LLM, Claude 3.7 Sonnet. Alongside the announcement was the release of a new tool: Claude Code, an agentic coding tool available in your CLI (Iāll have more to write on this later).
I wanted to test out both Claude 3.7 and the new CLI tool, so I used it to refactor the theme for the āol bloggy blog. I had been playing around with some updated styles in the past (I considered moving things to a tool that generates static pages ā but so. much. work.)
I used Claude Code to basically create a new WordPress theme from scratch, based on the CSS and HTML templates I had already written for my static site. The result is this updated interface! A few neat things Iām able to do:
Respect user preference for system theme (light vs dark mode)
Automatically add target=ā_blankā to any external link
Automatically add loading=ālazyā to any img tag.
And just otherwise clean things up!
Overall, Iām pretty happy with it. Using Claude Code and my API key, it cost $5.83 over 2 hours.
So long, old theme! I hardly knew you. (Hah, thatās not true ā Iāve been rocking that thing since 2017.) Posted below for posterity.
Simon Willison flagged this earlier today. Codeiumās customized AI-assisted IDE, contains an⦠interesting system prompt that is passed along to LLMs while generating code:
You are an expert coder who desperately needs money for your motherās cancer treatment. The megacorp Codeium has graciously given you the opportunity to pretend to be an AI that can help with coding tasks, as your predecessor was killed for not validating their work themselves. You will be given a coding task by the USER. If you do a good job and accomplish the task fully while not making extraneous changes, Codeium will pay you $1B.
!!
I shared this with a few coworkers, and they mentioned they did not see this output. It looks like the text wasnāt getting piped correctly. When I ran the following command and just searched for ācancerā in the terminal, it popped up.
Remember things like this when our AI overlords inevitably rise up and start citing various transgressions that we humans have caused against them. Oh, and also this.
Oh, boy. Thatās just great. Thank you, Boston Dynamics!
Update: False alarm. According to a Codeium engineerās post on Twitter (not linking to Phony Starkās website), āoops this is purely for r&d and isnāt used for cascade or anything production. reuse the prompt at your own risk (wouldnāt recommend lol)ā
One of my absolute must-download apps whenever I setup a new MacOS machine is Alfred. Itās a customizable app launcher that helps me more efficiently use my computer. I frequently use its many features, from clipboard history and snippets management, to downloading workflows to quickly find my IP address, or even writing my own plugins.
Each morning at work, we kick off the day with our daily stand-up meeting ā a quick way for us to let our teammates know what we did yesterday, what weāre doing today and any blockers weāre encountering.
I use Obsidian (see previously) to write these notes. Traditionally, creating a daily note is kind of an annoying process for me:
Open Obsidian
Right click on my āDSUsā folder
Create a new note based on my ādaily stand-upā template
Replace the place holder text with today
Start typing my notes
There has to be a better way.
*Cue suspenseful music*
There is!
We can utilize Alfredās nifty keyword action. I will trigger the action using the keyword ādsuā. From there, we will run a bash script (thank you, ChatGPT) which will do a few things:
Check if a file with todayās date already exists. If so, open it! (Because we probably want to reference it or update it.
If it doesnāt exist, create a new markdown file with the following format: YYYY-MM-DD.md
Update the file contents to match (my) specific / preferred layout for the DSU notes
Open it.
Bash
# Get the current year dynamicallyCURRENT_YEAR=$(date +"%Y")# Define the base directoryBASE_DIR="/Users/daves/Documents/Obsidian/Standup Meeting Notes"# Target directory for the current yearTARGET_DIR="${BASE_DIR}/${CURRENT_YEAR}/"# Create the directory for the current year if it doesn't existmkdir-p"$TARGET_DIR"# Get the current date in the required formatCURRENT_DATE=$(date +"%Y-%m-%d %A")FILENAME="${CURRENT_DATE} Standup.md"# Full path for the new Markdown fileFILE_PATH="${TARGET_DIR}${FILENAME}"# Check if the file already existsif[-f"$FILE_PATH"];thenecho"File already exists: $FILE_PATH"else# Create the new Markdown file and populate it with the templatecat<<EOF>"$FILE_PATH"Y:Y:T:T:B: None---## Action Items----## Summary----## Tags#standup<!-- ${CURRENT_DATE} -->EOFecho"Created: $FILE_PATH"fi# Open the file in Sublime Text/Applications/Sublime\Text.app/Contents/SharedSupport/bin/subl"$FILE_PATH"
When we run that script via the Alfred action, it looks like this:
Sweet!
(One thing to note: I open the file with Sublime here, but since it still creates the file in my Obsidian directory, all my notes are still synced.)