npx @bryceo/me

Building @bryceo/me, a TUI for my personal website

December 28, 2025

I've been really interested in finding an excuse to learn more about TUIs and specifically have been wanting to use OpenTUI. Since I have been recently revamping and working on my personal site for fun, I thought it would be interesting to create a TUI to browse information typically found on my personal website.

I had previously created a simple npx command to display "about me" information, but it was aimed at being as lightweight as possible and just getting basic information across. npx @bryceo/me was the original command, and this is what v1 looked like:

version 1.0

The Plan

v1.0 had a simple interaction of being able to download a PDF of my CV, but I wanted to create more interactions. The features I wanted to add were:

  1. Navigate to my website, github, and linkedin
  2. See my CV right there in the terminal
  3. Ability to send me a message directly from the terminal
  4. Navigate and read through blogs I have written directly in terminal

The Build

I started out by creating a new project with bun create tui and specifically used @opentui/solid as the render reconciler. SolidJS has also been on my list of technologies to checkout out, so this was a good hybrid case. I was going to have a "menu" screen and then sub-menus or actions for each item in the list. By using SolidJS I could effectively manage the stateful-ness of the app to ensure the appropriate screen was displayed and in sync.

Navigation Menu

First, I needed to start with a menu to navigate a set of options. The first items to do are the basic interactions of opening different URLs was really simple, I used open from sindresorhus for this which I used in a basic onSelect callback function like you'd do in a normal JSX application. No need for separate screens, I can just launch the browser from the main menu.

home

CV

Viewing my CV right in the terminal was also straight forward. Once selected, the application should navigate to a new screen and then I just needed to make sure I could easily take my CV from it's existing source(which is in a yml file) and generate some plain text to render. I also needed to make sure that the text box was scrollable for different view ports.

cv

Sending Message

This option brings you to a new screen with a large text area. You can type whatever you want and then when you hit SHIFT + ENTER, it will submit the message. In order to do this, I used Resend(which I also used for Kindle Notes Project). However, I needed to be careful here because this TUI is essentially a fully on the client, meaning I can't just bundle in environment variables or secrets. I took advantage of this learning opportunity to use a Cloudflare Worker. This way I can just have a single HTTP end point I need to call with my application and I can send off an email. So, whenever someone runs this TUI and sends a message, it just emails me the contents of the message.

message

Viewing Blogs

I wanted the ability to see the list of blogs from my site, and navigate into each one and read it. I did this by making a request to fetch all blog content from my website and then I can render the content directly into the TUI. This part is still a bit unpolished, right now when reading a blog you will just see the raw markdown content. Ideally, I want to do a full render of the blog(including images) in the terminal itself. Maybe even find a way to turn the images into ASCII to make it more terminal-like.

blogs

Take Away

I worked on this project for only a day or so but I really enjoyed it and I want to take it even further. I'd like to take interact more low-level and directly with the terminal's rendering layer and experimenting with some of the constraints. Specifically I'd like to get blogs to fully render in a comparable format with the bed and even render images. The highlight of this this project is that it allowed me to work with a handful of technologies I don't work with on a daily basis, such as OpenTUI, SolidJS, Cloudflare Workers, and even bun.

Want to try it? Run npx @bryceo/me