Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions web/app/[locale]/blog/emacsification-of-coding-agents/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useTranslations } from "next-intl";
import { getTranslations } from "next-intl/server";
import { buildAlternates } from "../../../../i18n/seo";
import { Link } from "../../../../i18n/navigation";

export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
const t = await getTranslations({
locale,
namespace: "blog.emacsificationOfCodingAgents",
});
const rawKeywords = t.raw("metaKeywords");
const keywords = Array.isArray(rawKeywords)
? rawKeywords.filter((keyword): keyword is string => typeof keyword === "string")
: [];

return {
title: t("metaTitle"),
description: t("metaDescription"),
keywords,
openGraph: {
title: t("metaTitle"),
description: t("metaDescription"),
type: "article",
publishedTime: "2026-06-19T00:00:00Z",
},
twitter: {
card: "summary_large_image",
title: t("metaTitle"),
description: t("metaDescription"),
},
alternates: buildAlternates(locale, "/blog/emacsification-of-coding-agents"),
};
}

export default function EmacsificationOfCodingAgentsPage() {
const t = useTranslations("blog.posts.emacsificationOfCodingAgents");
const tc = useTranslations("common");

return (
<>
<div className="mb-8">
<Link
href="/blog"
className="text-sm text-muted hover:text-foreground transition-colors"
>
&larr; {tc("backToBlog")}
</Link>
</div>

<h1>{t("title")}</h1>
<time dateTime="2026-06-19" className="text-sm text-muted">
{t("date")}
</time>

<p className="mt-6">{t("p1")}</p>
<p>{t("p2")}</p>
<p>{t("p3")}</p>
<p>{t("p4")}</p>
<p>
{t.rich("p5", {
sourceLink: (chunks) => (
<a href="https://x.com/lawrencecchen/status/2054882625760956603">
{chunks}
</a>
),
})}
</p>
</>
);
}
8 changes: 8 additions & 0 deletions web/app/[locale]/components/blog-posts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
export const blogPosts = [
{
slug: "emacsification-of-coding-agents",
key: "emacsificationOfCodingAgents",
title: "The Emacsification of Coding Agents",
date: "2026-06-19",
summary:
"Why open, terminal-native agent interfaces let developers compose their own workflows instead of waiting for one IDE to own them.",
},
{
slug: "cmux-history",
key: "cmuxHistory",
Expand Down
4 changes: 4 additions & 0 deletions web/app/lib/agent-page-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const englishOnlyPages = [
export const agentReadablePages = [
{ path: "/", title: "Home" },
{ path: "/blog", title: "Blog" },
{
path: "/blog/emacsification-of-coding-agents",
title: "The Emacsification of Coding Agents",
},
{ path: "/blog/cmux-history", title: "cmux history" },
{ path: "/blog/cmux-finder", title: "Introducing cmux Finder" },
{ path: "/blog/cmux-vault", title: "cmux Vault" },
Expand Down
3 changes: 2 additions & 1 deletion web/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export default function sitemap(): MetadataRoute.Sitemap {

const paths = [
{ path: "", lastModified: "2026-03-18", changeFrequency: "weekly" as const, priority: 1 },
{ path: "/blog", lastModified: "2026-06-02", changeFrequency: "weekly" as const, priority: 0.8 },
{ path: "/blog", lastModified: "2026-06-19", changeFrequency: "weekly" as const, priority: 0.8 },
{ path: "/blog/emacsification-of-coding-agents", lastModified: "2026-06-19", changeFrequency: "monthly" as const, priority: 0.7 },
{ path: "/blog/cmux-history", lastModified: "2026-06-02", changeFrequency: "monthly" as const, priority: 0.7 },
{ path: "/blog/cmux-finder", lastModified: "2026-05-22", changeFrequency: "monthly" as const, priority: 0.7 },
{ path: "/blog/cmux-vault", lastModified: "2026-05-22", changeFrequency: "monthly" as const, priority: 0.7 },
Expand Down
26 changes: 26 additions & 0 deletions web/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,22 @@
"metaTitle": "Blog",
"metaDescription": "News and updates from the cmux team",
"description": "News and updates from the cmux team",
"emacsificationOfCodingAgents": {
"metaTitle": "The Emacsification of Coding Agents",
"metaDescription": "Open, terminal-native agent interfaces let developers compose their own coding workflows instead of waiting for one IDE to own them.",
"metaKeywords": [
"emacsification of coding agents",
"cmux",
"AI coding agents",
"terminal coding agents",
"Claude Code",
"Codex",
"OpenCode",
"Gemini CLI",
"agent SDK",
"background agents"
]
},
"passkeyAuth": {
"metaTitle": "Passkey auth in the cmux browser",
"metaDescription": "cmux v0.64+ supports passkey authentication in browser panes and can import cookies from other browsers with cmux browser import.",
Expand Down Expand Up @@ -393,6 +409,16 @@
"metaDescription": "A native macOS terminal built on Ghostty, designed for running multiple AI coding agents side by side."
},
"posts": {
"emacsificationOfCodingAgents": {
"title": "The Emacsification of Coding Agents",
"summary": "Why open, terminal-native agent interfaces let developers compose their own workflows instead of waiting for one IDE to own them.",
"date": "June 19, 2026",
"p1": "Agent tools are moving into terminals because terminals are the shared interface every provider can support.",
"p2": "Claude Code, Codex, OpenCode, Gemini CLI, Aider, and custom SDK agents should not require a different dashboard for every run. The useful layer is a programmable terminal where panes, browsers, notifications, and workspace state are scriptable.",
"p3": "That is the emacsification: providers keep interfaces open, developers compose their own workflows, and the best patterns become reusable scripts instead of product lock-in.",
"p4": "cmux exists for that world. It stays close to the shell, adds native macOS panes and an embedded browser, and exposes a CLI/socket API so background agents can be launched, watched, resumed, and rearranged by code.",
"p5": "Source: <sourceLink>May 14, 2026 tweet</sourceLink>."
},
"passkeyAuth": {
"title": "Passkey auth in the cmux browser",
"summary": "cmux's embedded browser supports passkey authentication and can import cookies from other browsers with cmux browser import.",
Comment on lines 409 to 424

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing translations for 18 locales

web/i18n/routing.ts defines 20 supported locales, but this PR only adds blog.posts.emacsificationOfCodingAgents (and the matching meta-level blog.emacsificationOfCodingAgents) to en.json and ja.json. The remaining 18 locale files — zh-CN, zh-TW, ko, de, es, fr, it, da, pl, ru, bs, ar, no, pt-BR, th, tr, km, uk — are missing both the blog-index keys (blog.posts.emacsificationOfCodingAgents.title, .date, .summary) and the post-page meta keys (blog.emacsificationOfCodingAgents.metaTitle, etc.).

The blog index (web/app/[locale]/blog/page.tsx) calls t('posts.${post.key}.title'), t('posts.${post.key}.date'), and t('posts.${post.key}.summary') for every entry in blogPosts. Because emacsificationOfCodingAgents is now first in that array, any user hitting /zh-CN/blog (or any of the other 18 locale paths) will see a missing-key error or blank content for all three fields on the very first article card.

Rule Used: Flag production user-facing text that is not fully... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Expand Down
26 changes: 26 additions & 0 deletions web/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,33 @@
"metaTitle": "ブログ",
"metaDescription": "cmuxチームからのニュースとアップデート",
"description": "cmuxチームからのニュースとアップデート",
"emacsificationOfCodingAgents": {
"metaTitle": "コーディングエージェントのEmacs化",
"metaDescription": "オープンでターミナルネイティブなエージェントインターフェイスにより、開発者は1つのIDEに任せるのではなく自分のワークフローを組み立てられます。",
"metaKeywords": [
"コーディングエージェントのEmacs化",
"cmux",
"AIコーディングエージェント",
"ターミナル コーディングエージェント",
"Claude Code",
"Codex",
"OpenCode",
"Gemini CLI",
"agent SDK",
"background agents"
]
},
"posts": {
"emacsificationOfCodingAgents": {
"title": "コーディングエージェントのEmacs化",
"summary": "オープンでターミナルネイティブなエージェントインターフェイスが、1つのIDEに依存しない独自ワークフローを可能にする理由。",
"date": "2026年6月19日",
"p1": "エージェントツールはターミナルへ向かっています。ターミナルは、どのプロバイダーも対応できる共通インターフェイスだからです。",
"p2": "Claude Code、Codex、OpenCode、Gemini CLI、Aider、カスタムSDKエージェントの実行ごとに別々のダッシュボードは必要ありません。役に立つ層は、ペイン、ブラウザ、通知、ワークスペース状態をスクリプトで扱えるプログラマブルなターミナルです。",
"p3": "これがEmacs化です。プロバイダーはインターフェイスを開いたままにし、開発者は自分のワークフローを組み立て、良いパターンはプロダクトへのロックインではなく再利用できるスクリプトになります。",
"p4": "cmuxはその世界のためにあります。シェルに近いまま、ネイティブmacOSペインと組み込みブラウザを追加し、CLIとsocket APIでバックグラウンドエージェントを起動、監視、再開、並べ替えできるようにします。",
"p5": "出典:<sourceLink>2026年5月14日の投稿</sourceLink>。"
},
"cmdShiftU": {
"title": "Cmd+Shift+U",
"summary": "Cmd+Shift+Uがcmuxのワークスペース間で完了したエージェントにどうナビゲートするか。",
Expand Down
Loading