diff --git a/.gitignore b/.gitignore
index ced54ef5..071e93da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ zig-out/
# Node
node_modules/
+.next/
# Test outputs
tests/visual_output/
diff --git a/web/app/assets/images.d.ts b/web/app/assets/images.d.ts
new file mode 100644
index 00000000..9f3bf192
--- /dev/null
+++ b/web/app/assets/images.d.ts
@@ -0,0 +1,5 @@
+declare module "*.png" {
+ import type { StaticImageData } from "next/image";
+ const content: StaticImageData;
+ export default content;
+}
diff --git a/web/app/assets/landing-image.png b/web/app/assets/landing-image.png
new file mode 100644
index 00000000..3b03077b
Binary files /dev/null and b/web/app/assets/landing-image.png differ
diff --git a/web/app/blog/introducing-cmux/page.tsx b/web/app/blog/introducing-cmux/page.tsx
index 1632591c..474f1c7f 100644
--- a/web/app/blog/introducing-cmux/page.tsx
+++ b/web/app/blog/introducing-cmux/page.tsx
@@ -5,6 +5,35 @@ export const metadata: Metadata = {
title: "Introducing cmux",
description:
"A native macOS terminal built on Ghostty, designed for running multiple AI coding agents side by side.",
+ keywords: [
+ "cmux",
+ "terminal",
+ "macOS",
+ "Ghostty",
+ "libghostty",
+ "AI coding agents",
+ "Claude Code",
+ "vertical tabs",
+ "split panes",
+ "socket API",
+ ],
+ openGraph: {
+ title: "Introducing cmux",
+ description:
+ "A native macOS terminal built on Ghostty, designed for running multiple AI coding agents side by side.",
+ type: "article",
+ publishedTime: "2026-02-12T00:00:00Z",
+ url: "https://cmux.dev/blog/introducing-cmux",
+ },
+ twitter: {
+ card: "summary",
+ title: "Introducing cmux",
+ description:
+ "A native macOS terminal built on Ghostty, designed for running multiple AI coding agents side by side.",
+ },
+ alternates: {
+ canonical: "https://cmux.dev/blog/introducing-cmux",
+ },
};
export default function IntroducingCmuxPage() {
@@ -20,7 +49,7 @@ export default function IntroducingCmuxPage() {
Introducing cmux
-
+
cmux is a native macOS terminal application built on top of Ghostty,
@@ -31,7 +60,7 @@ export default function IntroducingCmuxPage() {
Why cmux?
Modern development workflows often involve running several agents at
- once — Claude Code, Codex, and other tools each in their own
+ once. Claude Code, Codex, and other tools each in their own
terminal. Keeping track of which ones need attention and switching
between them quickly is the problem cmux solves.
@@ -39,23 +68,23 @@ export default function IntroducingCmuxPage() {
Key features
- Vertical tabs — see all your terminals at a
+ Vertical tabs : see all your terminals at a
glance in a sidebar
- Notification rings — tabs flash when an agent
+ Notification rings : tabs flash when an agent
needs your input
- Split panes — horizontal and vertical splits
+ Split panes : horizontal and vertical splits
within each workspace
- Socket API — programmatic control for creating
+ Socket API : programmatic control for creating
tabs and sending input
- GPU-accelerated — powered by libghostty for
+ GPU-accelerated : powered by libghostty for
smooth rendering
diff --git a/web/app/blog/page.tsx b/web/app/blog/page.tsx
index d9ad9c4a..d7707772 100644
--- a/web/app/blog/page.tsx
+++ b/web/app/blog/page.tsx
@@ -7,6 +7,13 @@ export const metadata: Metadata = {
};
const posts = [
+ {
+ slug: "show-hn-launch",
+ title: "Launching cmux on Show HN",
+ date: "2026-02-21",
+ summary:
+ "cmux hit the front page, went viral in Japan, and shipped 18 releases in 48 hours.",
+ },
{
slug: "introducing-cmux",
title: "Introducing cmux",
diff --git a/web/app/blog/show-hn-launch/page.tsx b/web/app/blog/show-hn-launch/page.tsx
new file mode 100644
index 00000000..0800297b
--- /dev/null
+++ b/web/app/blog/show-hn-launch/page.tsx
@@ -0,0 +1,212 @@
+import type { Metadata } from "next";
+import Image from "next/image";
+import Link from "next/link";
+import { Tweet } from "react-tweet";
+import { DownloadButton } from "../../components/download-button";
+import { GitHubButton } from "../../components/github-button";
+import starHistory from "./star-history.png";
+
+export const metadata: Metadata = {
+ title: "Launching cmux on Show HN",
+ description:
+ "cmux launched on Hacker News, hit #2, went viral in Japan, and people started building extensions on the CLI. Here's what happened.",
+ keywords: [
+ "cmux",
+ "Show HN",
+ "Hacker News",
+ "terminal",
+ "macOS",
+ "Ghostty",
+ "libghostty",
+ "AI coding agents",
+ "Claude Code",
+ "Codex",
+ "launch",
+ "vertical tabs",
+ "notification rings",
+ ],
+ openGraph: {
+ title: "Launching cmux on Show HN",
+ description:
+ "cmux launched on Hacker News, hit #2, went viral in Japan, and people started building extensions on the CLI.",
+ type: "article",
+ publishedTime: "2026-02-21T00:00:00Z",
+ url: "https://cmux.dev/blog/show-hn-launch",
+ },
+ twitter: {
+ card: "summary",
+ title: "Launching cmux on Show HN",
+ description:
+ "cmux launched on Hacker News, hit #2, went viral in Japan, and people started building extensions on the CLI.",
+ },
+ alternates: {
+ canonical: "https://cmux.dev/blog/show-hn-launch",
+ },
+};
+
+export default function ShowHNLaunchPage() {
+ return (
+ <>
+
+
+ ← Back to blog
+
+
+
+
Launching cmux on Show HN
+
+
+
+ We posted cmux on{" "}
+ Show HN{" "}
+ on Feb 19:
+
+
+
+
+ I run a lot of Claude Code and Codex sessions in parallel. I was using
+ Ghostty with a bunch of split panes, and relying on native macOS
+ notifications to know when an agent needed me. But Claude Code's
+ notification body is always just "Claude is waiting for your
+ input" with no context, and with enough tabs open, I couldn't
+ even read the titles anymore.
+
+
+ I tried a few coding orchestrators but most of them were Electron/Tauri
+ apps and the performance bugged me. I also just prefer the terminal
+ since GUI orchestrators lock you into their workflow. So I built cmux as
+ a native macOS app in Swift/AppKit. It uses libghostty for terminal
+ rendering and reads your existing Ghostty config for themes, fonts,
+ colors, and more.
+
+
+ The main additions are the sidebar and notification system. The sidebar
+ has vertical tabs that show git branch, working directory, listening
+ ports, and the latest notification text for each workspace. The
+ notification system picks up terminal sequences (OSC 9/99/777) and has a
+ CLI (cmux notify) you can wire into agent hooks for Claude Code,
+ OpenCode, etc. When an agent is waiting, its pane gets a blue ring and
+ the tab lights up in the sidebar, so I can tell which one needs me
+ across splits and tabs. Cmd+Shift+U jumps to the most recent unread.
+
+
+ The in-app browser has a scriptable API. Agents can snapshot the
+ accessibility tree, get element refs, click, fill forms, evaluate JS,
+ and read console logs. You can split a browser pane next to your
+ terminal and have Claude Code interact with your dev server directly.
+
+
+ Everything is scriptable through the CLI and socket API: create
+ workspaces/tabs, split panes, send keystrokes, open URLs in the browser.
+
+
+
+
+ At peak it hit #2 on Hacker News. Mitchell Hashimoto shared it:
+
+
+
+
+
+ My favorite comment from the{" "}
+ HN thread:
+
+
+
+
+ Hey, this looks seriously awesome. Love the ideas here, specifically:
+ the programmability (I haven't tried it yet, but had been
+ considering learning tmux partly for this), layered UI, browser w/
+ api. Looking forward to giving this a spin. Also want to add that I
+ really appreciate Mitchell Hashimoto creating libghostty; it feels
+ like an exciting time to be a terminal user.
+
+
Some feedback (since you were asking for it elsewhere in the thread!):
+
+
+ It's not obvious/easy to open browser dev tools (cmd-alt-i
+ didn't work), and when I did find it (right click page →
+ inspect element) none of the controls were visible but I could see
+ stuff happening when I moved my mouse over the panel
+
+
+ Would be cool to borrow more of ghostty's behavior:
+
+
+ hotkey overrides – I have some things explicitly unmapped /
+ remapped in my ghostty config that conflict with some cmux
+ keybindings and weren't respected
+
+ Translation: "This looks good. A Ghostty-based terminal app
+ designed so you don't get lost running multiple CLIs like Claude
+ Code in parallel. The waiting-for-input panel gets a blue frame, and
+ it has its own notification system."
+
+
+
+ Another exciting thing was seeing people build on top of the cmux
+ CLI. sasha built a pi-cmux extension that shows model info, token
+ usage, and agent state in the sidebar:
+
+
+
+
+
+ Everything in cmux is scriptable through the CLI: creating workspaces,
+ sending keystrokes, controlling the browser, reading notifications.
+ Part of the cmux philosophy is being programmable and composable, so
+ people can customize the way they work with coding agents. The
+ state of the art for coding agents is changing fast, and you don't
+ want to be locked into an inflexible GUI orchestrator that can't
+ keep up.
+
+
+
+ If you're running multiple coding agents,{" "}
+ give cmux a try.
+