AI (whatever that means) is all the rage now. While I have been using Claude Code at work for a few months, I have been reluctant to use such tools on my side projects - I am unfortunately a perfectionist, and not knowing every bit (pun intended) of my projects does not feel right. However, that means it takes ages to get anything done, because it is never perfect, and I never finish anything, and I drop the projects after a few months, and, and. Bummer.

Back to last week.

I have been learning Korean for a few months, and something that constantly botters me is writing Hangul on my computer. While Ubuntu can give you a nice virtual keyboard, it is clunky. Changing my keyboard layout to Korean does not really work, because my physical keyboard is kind of ASCII (English EU, or something like that), and well, I don’t want to physically modify it, so it is hard to guess what I am typing. An external keyboard is a no go because my apartment is already cluttered. What is left are virtual keyboards on the web, but they are either ugly or riddled with ads. 🤮 I had no other choice other than create my own virtual Korean keyboard.

I started my project the old way, bootstraping a React + Typescript project, and researched how keyboard layouts in Korea look like. The standard layout is called Dubeolsik, and matches the layout I had setup on my Samsung phone, so it seemed like a sensible choice. Just like this blog, I used PicoCSS to give it a bit of style, and drafted the UI. I hardcoded the mapping between the Latin characters and their Hangul counterparts (jamo, thankfully there is an Unicode Block for them), and called it a day.

And then the problem began. Korean syllables are composed either of a consonant and a vowel (CV) or a consonant, a vowel and a consonant (CVC). But wait, there is more! Korean also has double vowels, double consonants, and double final consonants. That means we can have more than 11000+ combinations, and that is a lot. I imagined that you could do some magic with the Unicode values for each character to derive a syllable (like the formula to capitalize/lowercase ASCII chars everyone learns in CS101). I also imagined that, to build a syllable, I could use a state machine to build them - the logic is that the syllable either open or closed depending on the previous jamo and the current one, because they all syllables have to follow the CV/CVC pattern.

But as a father of two, with, barely any free time, this went veeeery slowly - until I turned to my friend Gemini, which is included in my Google One subscription. And guess what? In a couple of hours I could deliver the whole thing, the way I wanted it. Here is how it looks like - the title is not a Korean word, but a joke for myself:

Initial prototype

You can also see the real thing (and break it) here: kr.guh.me

To do that, I did have to relinquish some control over the code - after all, I did not write it myself - but I still reviewed it, and, most importantly, I kept control of the specification and the architecture of the project. This means that had to feed the agent a detailed specification of each feature, including test cases to validate them, and had to setup a workflow (skill) of how I wanted it to work. In this case, I chose that my agent use Test Driven Development, first implementing a harness to verify the behavior I want to implement, and then moving into the application code itself. This also included the tools the agent should use (tsc for type checking, eslint for linting, and vitest for testing). Finally, I setup the Chrome MCP server to let the agent use the real thing when I hit a weird edge case.

Basically, I used the agent to augment my capabilities and to automate boring work, while still retaining ownership of the artifacts produced by it. And before the pitchforks are raised: when I say boring work, it is not that I don’t find joy in writing code, but that my real reward is solving a problem, and code is just a means to that. Moreover, and perhaps most importantly, vibing let me:

  1. validate the editor implementation using a state machine without spending ∞ hours.
  2. find the goddamn documentation for the Hangul block in the Unicode Standard v17. This was particularly enriching, because I got to know the logic behind the design of the block (chapter 18.6), and that the smart guys that implemented it even gave us formula to join jamo (chapter 3.12).

Speeding up my learning is reason enough for me to continue using AI tools - answering myself, “to vibe is indeed the answer”. While we cannot ignore the economical, societal, and environmental impacts of AI, one cannots deny its utility, and that it is not going away anytime soon.