Skip to content

Instantly share code, notes, and snippets.

Show HN: cmux – Ghostty-based terminal with vertical tabs and notifications

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, and colors.

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 pi

@lawrencecchen
lawrencecchen / ws-repro.ts
Created December 4, 2025 04:52
Freestyle WebSocket repro - headers stripped
/**
* Minimal WebSocket Reproduction for Freestyle
*
* ISSUE: WebSocket connections fail through Freestyle web deployments.
*
* Expected behavior: WebSocket upgrade should work
* Actual behavior: Connection/Upgrade headers are stripped by the platform
*
* Test endpoints:
* GET /debug-headers - Shows what headers arrive (demonstrates stripped headers)
# vim bindings to focus splits
keybind = cmd+ctrl+h=goto_split:left
keybind = cmd+ctrl+j=goto_split:bottom
keybind = cmd+ctrl+k=goto_split:top
keybind = cmd+ctrl+l=goto_split:right
# delete to start of line
keybind = cmd+backspace=esc:w
keybind = global:cmd+control+.=toggle_quick_terminal
@lawrencecchen
lawrencecchen / ghostty config
Created January 21, 2025 03:59
lawrence's ghostty config
# vim bindings to focus splits
keybind = cmd+ctrl+h=goto_split:left
keybind = cmd+ctrl+j=goto_split:bottom
keybind = cmd+ctrl+k=goto_split:top
keybind = cmd+ctrl+l=goto_split:right
# delete to start of line
keybind = cmd+backspace=esc:w
keybind = global:cmd+control+.=toggle_quick_terminal
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { reactRouter } from "remix-hono/handler";
// @ts-ignore
import * as build from "./build/server";
const app = new Hono();
app.use(
"*",
@lawrencecchen
lawrencecchen / db.ts
Last active April 2, 2023 10:09
Kysely + Prisma + zod-prisma-types
import { Kysely } from "kysely";
import { PlanetScaleDialect } from "kysely-planetscale";
import { type z } from "zod";
import * as Models from "./prisma/generated/zod/modelSchema";
type RemoveSchema<S extends string> = S extends `${infer Prefix}Schema` ? Prefix : S;
export type Database = {
[K in keyof typeof Models as RemoveSchema<K>]: z.infer<(typeof Models)[K]>;
};
@lawrencecchen
lawrencecchen / kyselyAdapter.ts
Last active February 10, 2023 10:04
next-auth kysely adapter
import type { Kysely, RawBuilder } from "kysely";
import type { Account } from "next-auth";
import type {
Adapter,
AdapterSession,
VerificationToken,
AdapterUser,
} from "next-auth/adapters";
import type { DB } from "shared";
@lawrencecchen
lawrencecchen / useSwc.ts
Created September 3, 2022 08:16
react hook wrapper for swc
import { useEffect, useState } from "react";
import * as swc from "@swc/wasm-web";
let __initialized = false;
type SWC = Omit<typeof swc, "default" | "initSync">;
let __swc: SWC;
export default function useSwc() {
const [initialized, setInitialized] = useState(__initialized);
const [_swc, setSwc] = useState<SWC>(__swc);
@lawrencecchen
lawrencecchen / LLink.tsx
Created August 22, 2022 03:11
a next.js link that can be disabled.
@lawrencecchen
lawrencecchen / AutosizeTextarea.tsx
Last active February 27, 2023 02:47
autosize with react
import autosize from "autosize";
import { forwardRef, useEffect, useRef } from "react";
const AutosizeTextarea = forwardRef<
HTMLTextAreaElement,
React.DetailedHTMLProps<
React.TextareaHTMLAttributes<HTMLTextAreaElement>,
HTMLTextAreaElement
> & {
onResize?: (target: HTMLTextAreaElement) => void;