Skip to main content
Back to projects

Live

Terminal Portfolio

An interactive, SSH-accessible version of this portfolio — built in Go with the Charm ecosystem. No browser required.

GoBubble TeaWishSSH

Try it now

Paste this into your terminal. No auth, no setup, no catch.

$ ssh tui.arkadiuszjuszczyk.comView source

The idea

Most developer portfolios live in the browser. Mine does too — but I wanted a second version that speaks to the people who spend most of their day in the terminal. The kind of engineers and tech recruiters who would appreciate seeing a portfolio rendered in their favorite tool. So I built one you can access over SSH.

How it works

When you run ssh tui.arkadiuszjuszczyk.com, you're connecting to a custom SSH server — not a Linux box with a shell. The server accepts your connection, skips authentication entirely, and instead of dropping you into bash, it launches an interactive TUI application attached to your terminal session. You navigate with your keyboard, browse my experience, projects, and stack — then quit when you're done. No account, no browser, no JavaScript.

The stack

The server is written in Go, using the Charm ecosystem — a set of libraries purpose-built for terminal applications.

  • Wish handles the SSH server layer, accepting connections and managing sessions.
  • Bubble Tea is the TUI framework — it follows the Elm architecture (Model, Update, View) which makes state management clean and predictable.
  • Lip Gloss handles styling — think CSS but for terminal output: colors, padding, borders, alignment.
  • Bubbles provides pre-built components like lists, viewports, and text inputs.

Why Go

I could have built this in TypeScript (my day-to-day language) using ssh2 and Ink. But I specifically chose Go for two reasons: the Charm ecosystem is the most mature and polished toolchain for this exact use case — Wish + Bubble Tea gives you an SSH-to-TUI pipeline in about 20 lines of code. And I wanted to learn Go through a real project, not tutorials. A self-contained server with clear inputs and outputs turned out to be the perfect first Go project.

The architecture

The application is a single Go binary. When it starts, it spins up an SSH server on port 22. For each incoming connection, Wish creates a session and hands it off to Bubble Tea, which allocates a pseudo-terminal (PTY) and begins rendering frames using ANSI escape codes. The TUI detects your terminal size, responds to keypresses, and renders the interface — all over the existing SSH channel. There's no shell, no filesystem access, no commands to run. It's a read-only, interactive application that happens to be delivered over SSH.

Deployment

The server runs on a small VPS with the domain tui.arkadiuszjuszczyk.com pointed at it. The Go binary is compiled, uploaded, and managed with systemd. Port 22 is exposed directly — no reverse proxy needed since SSH handles its own protocol. The entire infrastructure cost is a few dollars a month.

Things that didn't go as planned

The build-in-public version, not the polished architecture diagram.

  • Ubuntu 24.04 silently ignored my sshd_config. I set Port 2222 in /etc/ssh/sshd_config, restarted sshd, and was surprised port 22 was still listening. Ubuntu 24.04 switched SSH to systemd socket activation by default — the Port directive in sshd_config gets overridden by the socket unit. The fix was systemctl disable ssh.socket and re-enabling the classic service.
  • Colors were stripped on first deploy. Everything worked locally but came through as plain white text once deployed. The issue: Lip Gloss auto-detects terminal color capabilities from the process's stdout — but under systemd, stdout isn't a real terminal, so it falls back to no colors. Fix was using a per-session renderer via bubbletea.MakeRenderer(s) so each SSH client's actual terminal capabilities get respected.
  • Clipboard copy over SSH. I wanted the contact tab's "enter to copy" to actually work. You can't open a browser on the client side from an SSH session, but you can use OSC 52 — an escape sequence that asks the terminal to put text on the user's clipboard. It's supported by iTerm2, Kitty, WezTerm, Windows Terminal and a few others. The URL links also use OSC 8 for proper clickable hyperlinks in terminals that support it.

What I learned

Building this taught me Go's approach to interfaces, struct composition, and message passing — all core patterns that Bubble Tea uses heavily. It also gave me a deeper understanding of how SSH works under the hood: key exchange, PTY allocation, channel multiplexing. And honestly, it reminded me why I got into engineering in the first place — building something that makes people go "wait, you can do that?"

Open to ambitious projects and interesting conversations

Let's connect