feat(web): add i18n support to landing page with Simplified Chinese

- Add dictionary-based i18n system (en/zh) with React Context provider
- Extract all hardcoded text from landing components into translation dictionaries
- Auto-detect browser language, persist preference in localStorage
- Add language switcher (EN/中文) to footer
- Add Noto Serif SC font for Chinese serif headings
- Rewrite about page Chinese copy with user-provided translation
This commit is contained in:
Jiayuan 2026-04-01 05:47:40 +08:00
parent 0b4c6b3910
commit 7e2b328e3c
15 changed files with 962 additions and 351 deletions

View file

@ -1,56 +1,46 @@
"use client";
import Link from "next/link";
import { LandingHeader } from "@/features/landing/components/landing-header";
import { LandingFooter } from "@/features/landing/components/landing-footer";
import { GitHubMark, githubUrl } from "@/features/landing/components/shared";
import { useLocale } from "@/features/landing/i18n";
export default function AboutPage() {
const { t } = useLocale();
const n = t.about.nameLine;
return (
<>
<LandingHeader variant="light" />
<main className="bg-white text-[#0a0d12]">
<div className="mx-auto max-w-[720px] px-4 py-16 sm:px-6 sm:py-20 lg:py-24">
<h1 className="font-[family-name:var(--font-serif)] text-[2.6rem] leading-[1.05] tracking-[-0.03em] sm:text-[3.4rem]">
About Multica
{t.about.title}
</h1>
<div className="mt-8 space-y-6 text-[15px] leading-[1.8] text-[#0a0d12]/70 sm:text-[16px]">
<p>
Multica <strong className="font-semibold text-[#0a0d12]">Mul</strong>tiplexed
Information and{" "}
<strong className="font-semibold text-[#0a0d12]">C</strong>omputing{" "}
<strong className="font-semibold text-[#0a0d12]">A</strong>gent.
</p>
<p>
The name is a nod to Multics, the pioneering operating system of
the 1960s that introduced time-sharing letting multiple users
share a single machine as if each had it to themselves. Unix was
born as a deliberate simplification of Multics: one user, one task,
one elegant philosophy.
</p>
<p>
We think the same inflection is happening again. For decades,
software teams have been single-threaded one engineer, one task,
one context switch at a time. AI agents change that equation.
Multica brings time-sharing back, but for an era where the
&ldquo;users&rdquo; multiplexing the system are both humans and
autonomous agents.
</p>
<p>
In Multica, agents are first-class teammates. They get assigned
issues, report progress, raise blockers, and ship code just like
their human colleagues. The assignee picker, the activity timeline,
the task lifecycle, and the runtime infrastructure are all built
around this idea from day one.
</p>
<p>
Like Multics before it, the bet is on multiplexing: a small team
shouldn&apos;t feel small. With the right system, two engineers and
a fleet of agents can move like twenty.
</p>
<p>
The platform is fully open source and self-hostable. Your data
stays on your infrastructure. Inspect every line, extend the API,
bring your own LLM providers, and contribute back to the community.
{n.prefix}
<strong className="font-semibold text-[#0a0d12]">
{n.mul}
</strong>
{n.tiplexed}
<strong className="font-semibold text-[#0a0d12]">
{n.i}
</strong>
{n.nformationAnd}
<strong className="font-semibold text-[#0a0d12]">
{n.c}
</strong>
{n.omputing}
<strong className="font-semibold text-[#0a0d12]">
{n.a}
</strong>
{n.gent}
</p>
{t.about.paragraphs.map((p, i) => (
<p key={i}>{p}</p>
))}
</div>
<div className="mt-12">
@ -61,7 +51,7 @@ export default function AboutPage() {
className="inline-flex items-center gap-2.5 rounded-[12px] bg-[#0a0d12] px-5 py-3 text-[14px] font-semibold text-white transition-colors hover:bg-[#0a0d12]/88"
>
<GitHubMark className="size-4" />
View on GitHub
{t.about.cta}
</Link>
</div>
</div>

View file

@ -1,81 +1,26 @@
"use client";
import { LandingHeader } from "@/features/landing/components/landing-header";
import { LandingFooter } from "@/features/landing/components/landing-footer";
const changelog = [
{
version: "0.1.3",
date: "2026-03-31",
title: "Agent Intelligence",
changes: [
"Trigger agents via @mention in comments",
"Stream live agent output to issue detail page",
"Rich text editor — mentions, link paste, emoji reactions, collapsible threads",
"File upload with S3 + CloudFront signed URLs and attachment tracking",
"Agent-driven repo checkout with bare clone cache for task isolation",
"Batch operations for issue list view",
"Daemon authentication and security hardening",
],
},
{
version: "0.1.2",
date: "2026-03-28",
title: "Collaboration",
changes: [
"Email verification login and browser-based CLI auth",
"Multi-workspace daemon with hot-reload",
"Runtime dashboard with usage charts and activity heatmaps",
"Subscriber-driven notification model replacing hardcoded triggers",
"Unified activity timeline with threaded comment replies",
"Kanban board redesign with drag sorting, filters, and display settings",
"Human-readable issue identifiers (e.g. JIA-1)",
"Skill import from ClawHub and Skills.sh",
],
},
{
version: "0.1.1",
date: "2026-03-25",
title: "Core Platform",
changes: [
"Multi-workspace switching and creation",
"Agent management UI with skills, tools, and triggers",
"Unified agent SDK supporting Claude Code and Codex backends",
"Comment CRUD with real-time WebSocket updates",
"Task service layer and daemon REST protocol",
"Event bus with workspace-scoped WebSocket isolation",
"Inbox notifications with unread badge and archive",
"CLI with cobra subcommands for workspace and issue management",
],
},
{
version: "0.1.0",
date: "2026-03-22",
title: "Foundation",
changes: [
"Go backend with REST API, JWT auth, and real-time WebSocket",
"Next.js frontend with Linear-inspired UI",
"Issues with board and list views and drag-and-drop kanban",
"Agents, Inbox, and Settings pages",
"One-click setup, migration CLI, and seed tool",
"Comprehensive test suite — Go unit/integration, Vitest, Playwright E2E",
],
},
];
import { useLocale } from "@/features/landing/i18n";
export default function ChangelogPage() {
const { t } = useLocale();
return (
<>
<LandingHeader variant="light" />
<main className="bg-white text-[#0a0d12]">
<div className="mx-auto max-w-[720px] px-4 py-16 sm:px-6 sm:py-20 lg:py-24">
<h1 className="font-[family-name:var(--font-serif)] text-[2.6rem] leading-[1.05] tracking-[-0.03em] sm:text-[3.4rem]">
Changelog
{t.changelog.title}
</h1>
<p className="mt-4 text-[15px] leading-7 text-[#0a0d12]/60 sm:text-[16px]">
New updates and improvements to Multica.
{t.changelog.subtitle}
</p>
<div className="mt-16 space-y-16">
{changelog.map((release) => (
{t.changelog.entries.map((release) => (
<div key={release.version} className="relative">
<div className="flex items-baseline gap-3">
<span className="text-[13px] font-semibold tabular-nums">

View file

@ -1,4 +1,5 @@
import { Instrument_Serif } from "next/font/google";
import { Instrument_Serif, Noto_Serif_SC } from "next/font/google";
import { LocaleProvider } from "@/features/landing/i18n";
const instrumentSerif = Instrument_Serif({
subsets: ["latin"],
@ -6,14 +7,20 @@ const instrumentSerif = Instrument_Serif({
variable: "--font-serif",
});
const notoSerifSC = Noto_Serif_SC({
subsets: ["latin"],
weight: "400",
variable: "--font-serif-zh",
});
export default function LandingLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className={`${instrumentSerif.variable} h-full overflow-x-hidden overflow-y-auto bg-white`}>
{children}
<div className={`${instrumentSerif.variable} ${notoSerifSC.variable} h-full overflow-x-hidden overflow-y-auto bg-white`}>
<LocaleProvider>{children}</LocaleProvider>
</div>
);
}

View file

@ -2,42 +2,10 @@
import { useState } from "react";
import { cn } from "@/lib/utils";
const faqs = [
{
question: "What coding agents does Multica support?",
answer:
"Multica currently supports Claude Code and OpenAI Codex out of the box. The daemon auto-detects whichever CLIs you have installed. More backends are on the roadmap — and since it's open source, you can add your own.",
},
{
question: "Do I need to self-host, or is there a cloud version?",
answer:
"Both. You can self-host Multica on your own infrastructure with Docker Compose or Kubernetes, or use our hosted cloud version. Your data, your choice.",
},
{
question:
"How is this different from just using Claude Code or Codex directly?",
answer:
"Coding agents are great at executing. Multica adds the management layer: task queues, team coordination, skill reuse, runtime monitoring, and a unified view of what every agent is doing. Think of it as the project manager for your agents.",
},
{
question: "Can agents work on long-running tasks autonomously?",
answer:
"Yes. Multica manages the full task lifecycle — enqueue, claim, execute, complete or fail. Agents report blockers proactively and stream progress in real time. You can check in whenever you want or let them run overnight.",
},
{
question: "Is my code safe? Where does agent execution happen?",
answer:
"Agent execution happens on your machine (local daemon) or your own cloud infrastructure. Code never passes through Multica servers. The platform only coordinates task state and broadcasts events.",
},
{
question: "How many agents can I run?",
answer:
"As many as your hardware supports. Each agent has configurable concurrency limits, and you can connect multiple machines as runtimes. There are no artificial caps in the open source version.",
},
];
import { useLocale } from "../i18n";
export function FAQSection() {
const { t } = useLocale();
const [openIndex, setOpenIndex] = useState<number | null>(null);
return (
@ -45,16 +13,16 @@ export function FAQSection() {
<div className="mx-auto max-w-[860px] px-4 py-24 sm:px-6 sm:py-32 lg:py-40">
<div className="text-center">
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[#0a0d12]/40">
FAQ
{t.faq.label}
</p>
<h2 className="mt-4 font-[family-name:var(--font-serif)] text-[2.6rem] leading-[1.05] tracking-[-0.03em] sm:text-[3.4rem] lg:text-[4.2rem]">
Questions & answers.
{t.faq.headline}
</h2>
</div>
<div className="mt-14 divide-y divide-[#0a0d12]/10 sm:mt-16">
{faqs.map((faq, i) => (
<div key={faq.question}>
{t.faq.items.map((faq, i) => (
<div key={i}>
<button
onClick={() => setOpenIndex(openIndex === i ? null : i)}
className="flex w-full items-start justify-between gap-4 py-6 text-left"

View file

@ -19,6 +19,8 @@ import {
} from "lucide-react";
import { cn } from "@/lib/utils";
import { ImageIcon } from "./shared";
import { useLocale } from "../i18n";
import type { LandingDict } from "../i18n";
import { StatusIcon } from "@/features/issues/components/status-icon";
import { PriorityIcon } from "@/features/issues/components/priority-icon";
import { STATUS_CONFIG } from "@/features/issues/config/status";
@ -945,109 +947,21 @@ function RuntimesVisual() {
);
}
const features = [
{
label: "TEAMMATES",
title: "Assign to an agent like you'd assign to a colleague",
description:
"Agents aren't passive tools — they're active participants. They have profiles, report status, create issues, comment, and change status. Your activity feed shows humans and agents working side by side.",
visual: TeammatesVisual,
cards: [
{
title: "Agents in the assignee picker",
description:
"Humans and agents appear in the same dropdown. Assigning work to an agent is no different from assigning it to a colleague.",
},
{
title: "Autonomous participation",
description:
"Agents create issues, leave comments, and update status on their own — not just when prompted.",
},
{
title: "Unified activity timeline",
description:
"One feed for the whole team. Human and agent actions are interleaved, so you always know what happened and who did it.",
},
],
},
{
label: "AUTONOMOUS",
title: "Set it and forget it — agents work while you sleep",
description:
"Not just prompt-response. Full task lifecycle management: enqueue, claim, start, complete or fail. Agents report blockers proactively and you get real-time progress via WebSocket.",
visual: AutonomousVisual,
bgImage: "/images/feature-bg-2.jpg",
cards: [
{
title: "Complete task lifecycle",
description:
"Every task flows through enqueue → claim → start → complete/fail. No silent failures — every transition is tracked and broadcast.",
},
{
title: "Proactive block reporting",
description:
"When an agent gets stuck, it raises a flag immediately. No more checking back hours later to find nothing happened.",
},
{
title: "Real-time progress streaming",
description:
"WebSocket-powered live updates. Watch agents work in real time, or check in whenever you want — the timeline is always current.",
},
],
},
{
label: "SKILLS",
title: "Every solution becomes a reusable skill for the whole team",
description:
"Skills are reusable capability definitions — code, config, and context bundled together. Write a skill once, and every agent on your team can use it. Your skill library compounds over time.",
visual: SkillsVisual,
bgImage: "/images/feature-bg-3.jpg",
cards: [
{
title: "Reusable skill definitions",
description:
"Package knowledge into skills that any agent can execute. Deploy to staging, write migrations, review PRs — all codified.",
},
{
title: "Team-wide sharing",
description:
"One person's skill is every agent's skill. Build once, benefit everywhere across your team.",
},
{
title: "Compound growth",
description:
"Day 1: you teach an agent to deploy. Day 30: every agent deploys, writes tests, and does code review. Your team's capabilities grow exponentially.",
},
],
},
{
label: "RUNTIMES",
title: "One dashboard for all your compute",
description:
"Local daemons and cloud runtimes, managed from a single panel. Real-time monitoring of online/offline status, usage charts, and activity heatmaps. Auto-detects local CLIs — plug in and go.",
visual: RuntimesVisual,
bgImage: "/images/feature-bg-4.jpg",
cards: [
{
title: "Unified runtime panel",
description:
"Local daemons and cloud runtimes in one view. No context switching between different management interfaces.",
},
{
title: "Real-time monitoring",
description:
"Online/offline status, usage charts, and activity heatmaps. Know exactly what your compute is doing at any moment.",
},
{
title: "Auto-detection & plug-and-play",
description:
"Multica detects available CLIs like Claude Code and Codex automatically. Connect a machine, and it's ready to work.",
},
],
},
];
function buildFeatures(t: LandingDict) {
const keys = ["teammates", "autonomous", "skills", "runtimes"] as const;
const visuals = [TeammatesVisual, AutonomousVisual, SkillsVisual, RuntimesVisual];
const bgImages = [undefined, "/images/feature-bg-2.jpg", "/images/feature-bg-3.jpg", "/images/feature-bg-4.jpg"];
return keys.map((key, i) => ({
...t.features[key],
visual: visuals[i]!,
bgImage: bgImages[i],
}));
}
export function FeaturesSection() {
const { t } = useLocale();
const features = buildFeatures(t);
const [activeIndex, setActiveIndex] = useState(0);
const panelRefs = useRef<(HTMLDivElement | null)[]>([]);

View file

@ -1,54 +1,32 @@
"use client";
import Link from "next/link";
import { useLocale } from "../i18n";
import { GitHubMark, githubUrl, heroButtonClassName } from "./shared";
const steps = [
{
number: "01",
title: "Sign up & create your workspace",
description:
"Enter your email, verify with a code, and you're in. Your workspace is created automatically — no setup wizard, no configuration forms.",
},
{
number: "02",
title: "Install the CLI & connect your machine",
description:
"Run multica login to authenticate, then multica daemon start. The daemon auto-detects Claude Code and Codex on your machine — plug in and go.",
},
{
number: "03",
title: "Create your first agent",
description:
"Give it a name, write instructions, attach skills, and set triggers. Choose when it activates: on assignment, on comment, or on mention.",
},
{
number: "04",
title: "Assign an issue and watch it work",
description:
"Pick your agent from the assignee dropdown — just like assigning to a teammate. The task is queued, claimed, and executed automatically. Watch progress in real time.",
},
];
export function HowItWorksSection() {
const { t } = useLocale();
return (
<section id="how-it-works" className="bg-[#05070b] text-white">
<div className="mx-auto max-w-[1320px] px-4 py-24 sm:px-6 sm:py-32 lg:px-8 lg:py-40">
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-white/40">
Get started
{t.howItWorks.label}
</p>
<h2 className="mt-4 font-[family-name:var(--font-serif)] text-[2.6rem] leading-[1.05] tracking-[-0.03em] sm:text-[3.4rem] lg:text-[4.2rem]">
Hire your first AI employee
{t.howItWorks.headlineMain}
<br />
<span className="text-white/40">in the next hour.</span>
<span className="text-white/40">{t.howItWorks.headlineFaded}</span>
</h2>
<div className="mt-20 grid gap-px overflow-hidden rounded-2xl border border-white/10 bg-white/10 sm:grid-cols-2 lg:grid-cols-4">
{steps.map((step) => (
{t.howItWorks.steps.map((step, i) => (
<div
key={step.number}
key={i}
className="flex flex-col bg-[#05070b] p-8 lg:p-10"
>
<span className="text-[13px] font-semibold tabular-nums text-white/28">
{step.number}
{String(i + 1).padStart(2, "0")}
</span>
<h3 className="mt-4 text-[17px] font-semibold leading-snug text-white sm:text-[18px]">
{step.title}
@ -62,7 +40,7 @@ export function HowItWorksSection() {
<div className="mt-14 flex flex-wrap items-center gap-4">
<Link href="/login" className={heroButtonClassName("solid")}>
Get started
{t.howItWorks.cta}
</Link>
<Link
href={githubUrl}
@ -71,7 +49,7 @@ export function HowItWorksSection() {
className={heroButtonClassName("ghost")}
>
<GitHubMark className="size-4" />
View on GitHub
{t.howItWorks.ctaGithub}
</Link>
</div>
</div>

View file

@ -2,28 +2,13 @@
import Link from "next/link";
import { MulticaIcon } from "@/components/multica-icon";
import { githubUrl } from "./shared";
const footerLinks = {
Product: [
{ label: "Features", href: "#features" },
{ label: "How it Works", href: "#how-it-works" },
{ label: "Changelog", href: "/changelog" },
],
Resources: [
{ label: "Documentation", href: githubUrl },
{ label: "API", href: githubUrl },
{ label: "Community", href: githubUrl },
],
Company: [
{ label: "About", href: "/about" },
{ label: "Open Source", href: "#open-source" },
{ label: "GitHub", href: githubUrl },
],
};
import { cn } from "@/lib/utils";
import { useLocale, locales, localeLabels } from "../i18n";
export function LandingFooter() {
const { t, locale, setLocale } = useLocale();
const groups = Object.values(t.footer.groups);
return (
<footer className="bg-[#0a0d12] text-white">
<div className="mx-auto max-w-[1320px] px-4 sm:px-6 lg:px-8">
@ -38,28 +23,27 @@ export function LandingFooter() {
</span>
</Link>
<p className="mt-4 max-w-[300px] text-[14px] leading-[1.7] text-white/50 sm:text-[15px]">
Project management for human + agent teams. Open source,
self-hostable, built for the future of work.
{t.footer.tagline}
</p>
<div className="mt-6">
<Link
href="/login"
className="inline-flex items-center justify-center rounded-[11px] bg-white px-5 py-2.5 text-[13px] font-semibold text-[#0a0d12] transition-colors hover:bg-white/88"
>
Get started
{t.footer.cta}
</Link>
</div>
</div>
{/* Right — link columns */}
<div className="grid flex-1 grid-cols-2 gap-8 sm:grid-cols-4">
{Object.entries(footerLinks).map(([group, links]) => (
<div key={group}>
{groups.map((group) => (
<div key={group.label}>
<h4 className="text-[12px] font-semibold uppercase tracking-[0.1em] text-white/40">
{group}
{group.label}
</h4>
<ul className="mt-4 flex flex-col gap-2.5">
{links.map((link) => (
{group.links.map((link) => (
<li key={link.label}>
<Link
href={link.href}
@ -78,11 +62,31 @@ export function LandingFooter() {
</div>
</div>
{/* Bottom: copyright */}
{/* Bottom: copyright + language switcher */}
<div className="flex items-center justify-between py-6">
<p className="text-[13px] text-white/36">
&copy; {new Date().getFullYear()} Multica. All rights reserved.
{t.footer.copyright.replace(
"{year}",
String(new Date().getFullYear()),
)}
</p>
<div className="flex items-center">
{locales.map((l, i) => (
<button
key={l}
onClick={() => setLocale(l)}
className={cn(
"px-1.5 py-1 text-[12px] font-medium transition-colors",
l === locale
? "text-white/70"
: "text-white/30 hover:text-white/50",
i > 0 && "border-l border-white/16",
)}
>
{localeLabels[l]}
</button>
))}
</div>
</div>
{/* Giant logo */}

View file

@ -3,6 +3,7 @@
import Link from "next/link";
import { MulticaIcon } from "@/components/multica-icon";
import { cn } from "@/lib/utils";
import { useLocale } from "../i18n";
import { GitHubMark, githubUrl, headerButtonClassName } from "./shared";
export function LandingHeader({
@ -10,11 +11,15 @@ export function LandingHeader({
}: {
variant?: "dark" | "light";
}) {
const { t } = useLocale();
return (
<header
className={cn(
"inset-x-0 top-0 z-30",
variant === "dark" ? "absolute bg-transparent" : "border-b border-[#0a0d12]/8 bg-white",
variant === "dark"
? "absolute bg-transparent"
: "border-b border-[#0a0d12]/8 bg-white",
)}
>
<div className="mx-auto flex h-[76px] max-w-[1320px] items-center justify-between px-4 sm:px-6 lg:px-8">
@ -44,13 +49,13 @@ export function LandingHeader({
className={headerButtonClassName("ghost", variant)}
>
<GitHubMark className="size-3.5" />
GitHub
{t.header.github}
</Link>
<Link
href="/login"
className={headerButtonClassName("solid", variant)}
>
Log in
{t.header.login}
</Link>
</div>
</div>

View file

@ -1,5 +1,8 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { useLocale } from "../i18n";
import {
ClaudeCodeLogo,
CodexLogo,
@ -9,6 +12,8 @@ import {
} from "./shared";
export function LandingHero() {
const { t } = useLocale();
return (
<div className="relative min-h-full overflow-hidden bg-[#05070b] text-white">
<LandingBackdrop />
@ -20,20 +25,18 @@ export function LandingHero() {
>
<div className="mx-auto max-w-[1120px] text-center">
<h1 className="font-[family-name:var(--font-serif)] text-[3.65rem] leading-[0.93] tracking-[-0.038em] text-white drop-shadow-[0_10px_34px_rgba(0,0,0,0.32)] sm:text-[4.85rem] lg:text-[6.4rem]">
Your next 10 hires
{t.hero.headlineLine1}
<br />
won&apos;t be human.
{t.hero.headlineLine2}
</h1>
<p className="mx-auto mt-7 max-w-[820px] text-[15px] leading-7 text-white/84 sm:text-[17px]">
Multica is an open-source platform that turns coding agents into
real teammates. Assign tasks, track progress, compound skills
manage your human + agent workforce in one place.
{t.hero.subheading}
</p>
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
<Link href="/login" className={heroButtonClassName("solid")}>
Start free trial
{t.hero.cta}
</Link>
<Link
href={githubUrl}
@ -48,7 +51,9 @@ export function LandingHero() {
</div>
<div className="mt-10 flex items-center justify-center gap-8">
<span className="text-[15px] text-white/50">Works with</span>
<span className="text-[15px] text-white/50">
{t.hero.worksWith}
</span>
<div className="flex items-center gap-6">
<div className="flex items-center gap-2.5 text-white/80">
<ClaudeCodeLogo className="size-5" />
@ -62,7 +67,7 @@ export function LandingHero() {
</div>
<div id="preview" className="mt-10 sm:mt-12">
<ProductImage />
<ProductImage alt={t.hero.imageAlt} />
</div>
</section>
</main>
@ -84,14 +89,14 @@ function LandingBackdrop() {
);
}
function ProductImage() {
function ProductImage({ alt }: { alt: string }) {
return (
<div>
<div className="relative overflow-hidden border border-white/14">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/images/landing-hero.png"
alt="Multica board view — issues managed by humans and agents"
alt={alt}
className="block w-full"
/>
</div>

View file

@ -1,30 +1,12 @@
"use client";
import Link from "next/link";
import { useLocale } from "../i18n";
import { GitHubMark, githubUrl } from "./shared";
const openSourceHighlights = [
{
title: "Self-host anywhere",
description:
"Run Multica on your own infrastructure. Docker Compose, single binary, or Kubernetes — your data never leaves your network.",
},
{
title: "No vendor lock-in",
description:
"Bring your own LLM provider, swap agent backends, extend the API. You own the stack, top to bottom.",
},
{
title: "Transparent by default",
description:
"Every line of code is auditable. See exactly how your agents make decisions, how tasks are routed, and where your data flows.",
},
{
title: "Community-driven",
description:
"Built with the community, not just for it. Contribute skills, integrations, and agent backends that benefit everyone.",
},
];
export function OpenSourceSection() {
const { t } = useLocale();
return (
<section id="open-source" className="bg-white text-[#0a0d12]">
<div className="mx-auto max-w-[1320px] px-4 py-24 sm:px-6 sm:py-32 lg:px-8 lg:py-40">
@ -32,17 +14,15 @@ export function OpenSourceSection() {
{/* Left column — heading + CTA */}
<div className="lg:w-[480px] lg:shrink-0">
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[#0a0d12]/40">
Open source
{t.openSource.label}
</p>
<h2 className="mt-4 font-[family-name:var(--font-serif)] text-[2.6rem] leading-[1.05] tracking-[-0.03em] sm:text-[3.4rem] lg:text-[4.2rem]">
Open source
{t.openSource.headlineLine1}
<br />
for all.
{t.openSource.headlineLine2}
</h2>
<p className="mt-6 max-w-[420px] text-[15px] leading-7 text-[#0a0d12]/60 sm:text-[16px]">
Multica is fully open source. Inspect every line, self-host on
your own terms, and shape the future of human + agent
collaboration.
{t.openSource.description}
</p>
<div className="mt-8 flex flex-wrap items-center gap-3">
<Link
@ -52,7 +32,7 @@ export function OpenSourceSection() {
className="inline-flex items-center justify-center gap-2.5 rounded-[12px] bg-[#0a0d12] px-5 py-3 text-[14px] font-semibold text-white transition-colors hover:bg-[#0a0d12]/88"
>
<GitHubMark className="size-4" />
Star on GitHub
{t.openSource.cta}
</Link>
</div>
</div>
@ -60,7 +40,7 @@ export function OpenSourceSection() {
{/* Right column — highlight grid */}
<div className="flex-1">
<div className="grid gap-px overflow-hidden rounded-2xl border border-[#0a0d12]/8 bg-[#0a0d12]/8 sm:grid-cols-2">
{openSourceHighlights.map((item) => (
{t.openSource.highlights.map((item) => (
<div key={item.title} className="bg-white p-8 lg:p-10">
<h3 className="text-[17px] font-semibold leading-snug text-[#0a0d12] sm:text-[18px]">
{item.title}

View file

@ -0,0 +1,51 @@
"use client";
import { createContext, useContext, useState, useCallback } from "react";
import { en } from "./en";
import { zh } from "./zh";
import type { LandingDict, Locale } from "./types";
const dictionaries: Record<Locale, LandingDict> = { en, zh };
const STORAGE_KEY = "multica-locale";
function getInitialLocale(): Locale {
if (typeof window === "undefined") return "en";
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === "en" || stored === "zh") return stored;
// Detect from browser language
const lang = navigator.language;
if (lang.startsWith("zh")) return "zh";
return "en";
}
type LocaleContextValue = {
locale: Locale;
t: LandingDict;
setLocale: (locale: Locale) => void;
};
const LocaleContext = createContext<LocaleContextValue | null>(null);
export function LocaleProvider({ children }: { children: React.ReactNode }) {
const [locale, setLocaleState] = useState<Locale>(getInitialLocale);
const setLocale = useCallback((l: Locale) => {
setLocaleState(l);
localStorage.setItem(STORAGE_KEY, l);
}, []);
return (
<LocaleContext.Provider
value={{ locale, t: dictionaries[locale], setLocale }}
>
{children}
</LocaleContext.Provider>
);
}
export function useLocale() {
const ctx = useContext(LocaleContext);
if (!ctx) throw new Error("useLocale must be used within LocaleProvider");
return ctx;
}

View file

@ -0,0 +1,333 @@
import { githubUrl } from "../components/shared";
import type { LandingDict } from "./types";
export const en: LandingDict = {
header: {
github: "GitHub",
login: "Log in",
},
hero: {
headlineLine1: "Your next 10 hires",
headlineLine2: "won\u2019t be human.",
subheading:
"Multica is an open-source platform that turns coding agents into real teammates. Assign tasks, track progress, compound skills \u2014 manage your human + agent workforce in one place.",
cta: "Start free trial",
worksWith: "Works with",
imageAlt: "Multica board view \u2014 issues managed by humans and agents",
},
features: {
teammates: {
label: "TEAMMATES",
title: "Assign to an agent like you\u2019d assign to a colleague",
description:
"Agents aren\u2019t passive tools \u2014 they\u2019re active participants. They have profiles, report status, create issues, comment, and change status. Your activity feed shows humans and agents working side by side.",
cards: [
{
title: "Agents in the assignee picker",
description:
"Humans and agents appear in the same dropdown. Assigning work to an agent is no different from assigning it to a colleague.",
},
{
title: "Autonomous participation",
description:
"Agents create issues, leave comments, and update status on their own \u2014 not just when prompted.",
},
{
title: "Unified activity timeline",
description:
"One feed for the whole team. Human and agent actions are interleaved, so you always know what happened and who did it.",
},
],
},
autonomous: {
label: "AUTONOMOUS",
title: "Set it and forget it \u2014 agents work while you sleep",
description:
"Not just prompt-response. Full task lifecycle management: enqueue, claim, start, complete or fail. Agents report blockers proactively and you get real-time progress via WebSocket.",
cards: [
{
title: "Complete task lifecycle",
description:
"Every task flows through enqueue \u2192 claim \u2192 start \u2192 complete/fail. No silent failures \u2014 every transition is tracked and broadcast.",
},
{
title: "Proactive block reporting",
description:
"When an agent gets stuck, it raises a flag immediately. No more checking back hours later to find nothing happened.",
},
{
title: "Real-time progress streaming",
description:
"WebSocket-powered live updates. Watch agents work in real time, or check in whenever you want \u2014 the timeline is always current.",
},
],
},
skills: {
label: "SKILLS",
title: "Every solution becomes a reusable skill for the whole team",
description:
"Skills are reusable capability definitions \u2014 code, config, and context bundled together. Write a skill once, and every agent on your team can use it. Your skill library compounds over time.",
cards: [
{
title: "Reusable skill definitions",
description:
"Package knowledge into skills that any agent can execute. Deploy to staging, write migrations, review PRs \u2014 all codified.",
},
{
title: "Team-wide sharing",
description:
"One person\u2019s skill is every agent\u2019s skill. Build once, benefit everywhere across your team.",
},
{
title: "Compound growth",
description:
"Day 1: you teach an agent to deploy. Day 30: every agent deploys, writes tests, and does code review. Your team\u2019s capabilities grow exponentially.",
},
],
},
runtimes: {
label: "RUNTIMES",
title: "One dashboard for all your compute",
description:
"Local daemons and cloud runtimes, managed from a single panel. Real-time monitoring of online/offline status, usage charts, and activity heatmaps. Auto-detects local CLIs \u2014 plug in and go.",
cards: [
{
title: "Unified runtime panel",
description:
"Local daemons and cloud runtimes in one view. No context switching between different management interfaces.",
},
{
title: "Real-time monitoring",
description:
"Online/offline status, usage charts, and activity heatmaps. Know exactly what your compute is doing at any moment.",
},
{
title: "Auto-detection & plug-and-play",
description:
"Multica detects available CLIs like Claude Code and Codex automatically. Connect a machine, and it\u2019s ready to work.",
},
],
},
},
howItWorks: {
label: "Get started",
headlineMain: "Hire your first AI employee",
headlineFaded: "in the next hour.",
steps: [
{
title: "Sign up & create your workspace",
description:
"Enter your email, verify with a code, and you\u2019re in. Your workspace is created automatically \u2014 no setup wizard, no configuration forms.",
},
{
title: "Install the CLI & connect your machine",
description:
"Run multica login to authenticate, then multica daemon start. The daemon auto-detects Claude Code and Codex on your machine \u2014 plug in and go.",
},
{
title: "Create your first agent",
description:
"Give it a name, write instructions, attach skills, and set triggers. Choose when it activates: on assignment, on comment, or on mention.",
},
{
title: "Assign an issue and watch it work",
description:
"Pick your agent from the assignee dropdown \u2014 just like assigning to a teammate. The task is queued, claimed, and executed automatically. Watch progress in real time.",
},
],
cta: "Get started",
ctaGithub: "View on GitHub",
},
openSource: {
label: "Open source",
headlineLine1: "Open source",
headlineLine2: "for all.",
description:
"Multica is fully open source. Inspect every line, self-host on your own terms, and shape the future of human + agent collaboration.",
cta: "Star on GitHub",
highlights: [
{
title: "Self-host anywhere",
description:
"Run Multica on your own infrastructure. Docker Compose, single binary, or Kubernetes \u2014 your data never leaves your network.",
},
{
title: "No vendor lock-in",
description:
"Bring your own LLM provider, swap agent backends, extend the API. You own the stack, top to bottom.",
},
{
title: "Transparent by default",
description:
"Every line of code is auditable. See exactly how your agents make decisions, how tasks are routed, and where your data flows.",
},
{
title: "Community-driven",
description:
"Built with the community, not just for it. Contribute skills, integrations, and agent backends that benefit everyone.",
},
],
},
faq: {
label: "FAQ",
headline: "Questions & answers.",
items: [
{
question: "What coding agents does Multica support?",
answer:
"Multica currently supports Claude Code and OpenAI Codex out of the box. The daemon auto-detects whichever CLIs you have installed. More backends are on the roadmap \u2014 and since it\u2019s open source, you can add your own.",
},
{
question: "Do I need to self-host, or is there a cloud version?",
answer:
"Both. You can self-host Multica on your own infrastructure with Docker Compose or Kubernetes, or use our hosted cloud version. Your data, your choice.",
},
{
question:
"How is this different from just using Claude Code or Codex directly?",
answer:
"Coding agents are great at executing. Multica adds the management layer: task queues, team coordination, skill reuse, runtime monitoring, and a unified view of what every agent is doing. Think of it as the project manager for your agents.",
},
{
question: "Can agents work on long-running tasks autonomously?",
answer:
"Yes. Multica manages the full task lifecycle \u2014 enqueue, claim, execute, complete or fail. Agents report blockers proactively and stream progress in real time. You can check in whenever you want or let them run overnight.",
},
{
question: "Is my code safe? Where does agent execution happen?",
answer:
"Agent execution happens on your machine (local daemon) or your own cloud infrastructure. Code never passes through Multica servers. The platform only coordinates task state and broadcasts events.",
},
{
question: "How many agents can I run?",
answer:
"As many as your hardware supports. Each agent has configurable concurrency limits, and you can connect multiple machines as runtimes. There are no artificial caps in the open source version.",
},
],
},
footer: {
tagline:
"Project management for human + agent teams. Open source, self-hostable, built for the future of work.",
cta: "Get started",
groups: {
product: {
label: "Product",
links: [
{ label: "Features", href: "#features" },
{ label: "How it Works", href: "#how-it-works" },
{ label: "Changelog", href: "/changelog" },
],
},
resources: {
label: "Resources",
links: [
{ label: "Documentation", href: githubUrl },
{ label: "API", href: githubUrl },
{ label: "Community", href: githubUrl },
],
},
company: {
label: "Company",
links: [
{ label: "About", href: "/about" },
{ label: "Open Source", href: "#open-source" },
{ label: "GitHub", href: githubUrl },
],
},
},
copyright: "\u00a9 {year} Multica. All rights reserved.",
},
about: {
title: "About Multica",
nameLine: {
prefix: "Multica \u2014 ",
mul: "Mul",
tiplexed: "tiplexed ",
i: "I",
nformationAnd: "nformation and ",
c: "C",
omputing: "omputing ",
a: "A",
gent: "gent.",
},
paragraphs: [
"The name is a nod to Multics, the pioneering operating system of the 1960s that introduced time-sharing \u2014 letting multiple users share a single machine as if each had it to themselves. Unix was born as a deliberate simplification of Multics: one user, one task, one elegant philosophy.",
"We think the same inflection is happening again. For decades, software teams have been single-threaded \u2014 one engineer, one task, one context switch at a time. AI agents change that equation. Multica brings time-sharing back, but for an era where the \u201cusers\u201d multiplexing the system are both humans and autonomous agents.",
"In Multica, agents are first-class teammates. They get assigned issues, report progress, raise blockers, and ship code \u2014 just like their human colleagues. The assignee picker, the activity timeline, the task lifecycle, and the runtime infrastructure are all built around this idea from day one.",
"Like Multics before it, the bet is on multiplexing: a small team shouldn\u2019t feel small. With the right system, two engineers and a fleet of agents can move like twenty.",
"The platform is fully open source and self-hostable. Your data stays on your infrastructure. Inspect every line, extend the API, bring your own LLM providers, and contribute back to the community.",
],
cta: "View on GitHub",
},
changelog: {
title: "Changelog",
subtitle: "New updates and improvements to Multica.",
entries: [
{
version: "0.1.3",
date: "2026-03-31",
title: "Agent Intelligence",
changes: [
"Trigger agents via @mention in comments",
"Stream live agent output to issue detail page",
"Rich text editor \u2014 mentions, link paste, emoji reactions, collapsible threads",
"File upload with S3 + CloudFront signed URLs and attachment tracking",
"Agent-driven repo checkout with bare clone cache for task isolation",
"Batch operations for issue list view",
"Daemon authentication and security hardening",
],
},
{
version: "0.1.2",
date: "2026-03-28",
title: "Collaboration",
changes: [
"Email verification login and browser-based CLI auth",
"Multi-workspace daemon with hot-reload",
"Runtime dashboard with usage charts and activity heatmaps",
"Subscriber-driven notification model replacing hardcoded triggers",
"Unified activity timeline with threaded comment replies",
"Kanban board redesign with drag sorting, filters, and display settings",
"Human-readable issue identifiers (e.g. JIA-1)",
"Skill import from ClawHub and Skills.sh",
],
},
{
version: "0.1.1",
date: "2026-03-25",
title: "Core Platform",
changes: [
"Multi-workspace switching and creation",
"Agent management UI with skills, tools, and triggers",
"Unified agent SDK supporting Claude Code and Codex backends",
"Comment CRUD with real-time WebSocket updates",
"Task service layer and daemon REST protocol",
"Event bus with workspace-scoped WebSocket isolation",
"Inbox notifications with unread badge and archive",
"CLI with cobra subcommands for workspace and issue management",
],
},
{
version: "0.1.0",
date: "2026-03-22",
title: "Foundation",
changes: [
"Go backend with REST API, JWT auth, and real-time WebSocket",
"Next.js frontend with Linear-inspired UI",
"Issues with board and list views and drag-and-drop kanban",
"Agents, Inbox, and Settings pages",
"One-click setup, migration CLI, and seed tool",
"Comprehensive test suite \u2014 Go unit/integration, Vitest, Playwright E2E",
],
},
],
},
};

View file

@ -0,0 +1,3 @@
export { LocaleProvider, useLocale } from "./context";
export { locales, localeLabels } from "./types";
export type { Locale, LandingDict } from "./types";

View file

@ -0,0 +1,95 @@
export type Locale = "en" | "zh";
export const locales: Locale[] = ["en", "zh"];
export const localeLabels: Record<Locale, string> = {
en: "EN",
zh: "\u4e2d\u6587",
};
type FeatureSection = {
label: string;
title: string;
description: string;
cards: { title: string; description: string }[];
};
type FooterGroup = {
label: string;
links: { label: string; href: string }[];
};
export type LandingDict = {
header: { github: string; login: string };
hero: {
headlineLine1: string;
headlineLine2: string;
subheading: string;
cta: string;
worksWith: string;
imageAlt: string;
};
features: {
teammates: FeatureSection;
autonomous: FeatureSection;
skills: FeatureSection;
runtimes: FeatureSection;
};
howItWorks: {
label: string;
headlineMain: string;
headlineFaded: string;
steps: { title: string; description: string }[];
cta: string;
ctaGithub: string;
};
openSource: {
label: string;
headlineLine1: string;
headlineLine2: string;
description: string;
cta: string;
highlights: { title: string; description: string }[];
};
faq: {
label: string;
headline: string;
items: { question: string; answer: string }[];
};
footer: {
tagline: string;
cta: string;
groups: {
product: FooterGroup;
resources: FooterGroup;
company: FooterGroup;
};
copyright: string;
};
about: {
title: string;
nameLine: {
prefix: string;
mul: string;
tiplexed: string;
i: string;
nformationAnd: string;
c: string;
omputing: string;
a: string;
gent: string;
};
paragraphs: string[];
cta: string;
};
changelog: {
title: string;
subtitle: string;
entries: {
version: string;
date: string;
title: string;
changes: string[];
}[];
};
};

View file

@ -0,0 +1,333 @@
import { githubUrl } from "../components/shared";
import type { LandingDict } from "./types";
export const zh: LandingDict = {
header: {
github: "GitHub",
login: "\u767b\u5f55",
},
hero: {
headlineLine1: "\u4f60\u7684\u4e0b\u4e00\u6279\u5458\u5de5",
headlineLine2: "\u4e0d\u662f\u4eba\u7c7b\u3002",
subheading:
"Multica \u662f\u4e00\u4e2a\u5f00\u6e90\u5e73\u53f0\uff0c\u5c06\u7f16\u7801 Agent \u53d8\u6210\u771f\u6b63\u7684\u961f\u53cb\u3002\u5206\u914d\u4efb\u52a1\u3001\u8ddf\u8e2a\u8fdb\u5ea6\u3001\u79ef\u7d2f\u6280\u80fd\u2014\u2014\u5728\u4e00\u4e2a\u5730\u65b9\u7ba1\u7406\u4f60\u7684\u4eba\u7c7b + Agent \u56e2\u961f\u3002",
cta: "\u514d\u8d39\u5f00\u59cb",
worksWith: "\u652f\u6301",
imageAlt: "Multica \u770b\u677f\u89c6\u56fe\u2014\u2014\u4eba\u7c7b\u548c Agent \u534f\u540c\u7ba1\u7406\u4efb\u52a1",
},
features: {
teammates: {
label: "\u56e2\u961f\u534f\u4f5c",
title: "\u50cf\u5206\u914d\u7ed9\u540c\u4e8b\u4e00\u6837\u5206\u914d\u7ed9 Agent",
description:
"Agent \u4e0d\u662f\u88ab\u52a8\u5de5\u5177\u2014\u2014\u5b83\u4eec\u662f\u4e3b\u52a8\u53c2\u4e0e\u8005\u3002\u5b83\u4eec\u62e5\u6709\u4e2a\u4eba\u8d44\u6599\u3001\u62a5\u544a\u72b6\u6001\u3001\u521b\u5efa Issue\u3001\u53d1\u8868\u8bc4\u8bba\u3001\u66f4\u65b0\u72b6\u6001\u3002\u4f60\u7684\u6d3b\u52a8\u6d41\u5c55\u793a\u4eba\u7c7b\u548c Agent \u5e76\u80a9\u5de5\u4f5c\u3002",
cards: [
{
title: "Agent \u51fa\u73b0\u5728\u6307\u6d3e\u4eba\u9009\u62e9\u5668\u4e2d",
description:
"\u4eba\u7c7b\u548c Agent \u51fa\u73b0\u5728\u540c\u4e00\u4e2a\u4e0b\u62c9\u83dc\u5355\u91cc\u3002\u628a\u4efb\u52a1\u5206\u914d\u7ed9 Agent \u548c\u5206\u914d\u7ed9\u540c\u4e8b\u6ca1\u6709\u4efb\u4f55\u533a\u522b\u3002",
},
{
title: "\u81ea\u4e3b\u53c2\u4e0e",
description:
"Agent \u4e3b\u52a8\u521b\u5efa Issue\u3001\u53d1\u8868\u8bc4\u8bba\u3001\u66f4\u65b0\u72b6\u6001\u2014\u2014\u800c\u4e0d\u662f\u53ea\u5728\u88ab\u63d0\u793a\u65f6\u624d\u884c\u52a8\u3002",
},
{
title: "\u7edf\u4e00\u7684\u6d3b\u52a8\u65f6\u95f4\u7ebf",
description:
"\u6574\u4e2a\u56e2\u961f\u5171\u7528\u4e00\u4e2a\u6d3b\u52a8\u6d41\u3002\u4eba\u7c7b\u548c Agent \u7684\u64cd\u4f5c\u4ea4\u66ff\u5c55\u793a\uff0c\u4f60\u59cb\u7ec8\u77e5\u9053\u53d1\u751f\u4e86\u4ec0\u4e48\u3001\u662f\u8c01\u505a\u7684\u3002",
},
],
},
autonomous: {
label: "\u81ea\u4e3b\u6267\u884c",
title: "\u8bbe\u7f6e\u540e\u65e0\u9700\u7ba1\u7406\u2014\u2014Agent \u5728\u4f60\u7761\u89c9\u65f6\u5de5\u4f5c",
description:
"\u4e0d\u53ea\u662f\u63d0\u793a-\u54cd\u5e94\u3002\u5b8c\u6574\u7684\u4efb\u52a1\u751f\u547d\u5468\u671f\u7ba1\u7406\uff1a\u5165\u961f\u3001\u9886\u53d6\u3001\u542f\u52a8\u3001\u5b8c\u6210\u6216\u5931\u8d25\u3002Agent \u4e3b\u52a8\u62a5\u544a\u963b\u585e\uff0c\u4f60\u901a\u8fc7 WebSocket \u83b7\u53d6\u5b9e\u65f6\u8fdb\u5ea6\u3002",
cards: [
{
title: "\u5b8c\u6574\u7684\u4efb\u52a1\u751f\u547d\u5468\u671f",
description:
"\u6bcf\u4e2a\u4efb\u52a1\u7ecf\u5386\u5165\u961f \u2192 \u9886\u53d6 \u2192 \u542f\u52a8 \u2192 \u5b8c\u6210/\u5931\u8d25\u3002\u6ca1\u6709\u65e0\u58f0\u5931\u8d25\u2014\u2014\u6bcf\u6b21\u72b6\u6001\u8f6c\u6362\u90fd\u88ab\u8ddf\u8e2a\u548c\u5e7f\u64ad\u3002",
},
{
title: "\u4e3b\u52a8\u62a5\u544a\u963b\u585e",
description:
"\u5f53 Agent \u9047\u5230\u56f0\u96be\u65f6\uff0c\u4f1a\u7acb\u5373\u53d1\u51fa\u8b66\u62a5\u3002\u4e0d\u7528\u7b49\u51e0\u4e2a\u5c0f\u65f6\u540e\u624d\u53d1\u73b0\u4ec0\u4e48\u90fd\u6ca1\u53d1\u751f\u3002",
},
{
title: "\u5b9e\u65f6\u8fdb\u5ea6\u63a8\u9001",
description:
"\u57fa\u4e8e WebSocket \u7684\u5b9e\u65f6\u66f4\u65b0\u3002\u5b9e\u65f6\u89c2\u770b Agent \u5de5\u4f5c\uff0c\u6216\u968f\u65f6\u67e5\u770b\u2014\u2014\u65f6\u95f4\u7ebf\u59cb\u7ec8\u662f\u6700\u65b0\u7684\u3002",
},
],
},
skills: {
label: "\u6280\u80fd\u5e93",
title: "\u6bcf\u4e2a\u89e3\u51b3\u65b9\u6848\u90fd\u6210\u4e3a\u5168\u56e2\u961f\u53ef\u590d\u7528\u7684\u6280\u80fd",
description:
"\u6280\u80fd\u662f\u53ef\u590d\u7528\u7684\u80fd\u529b\u5b9a\u4e49\u2014\u2014\u4ee3\u7801\u3001\u914d\u7f6e\u548c\u4e0a\u4e0b\u6587\u6253\u5305\u5728\u4e00\u8d77\u3002\u53ea\u9700\u7f16\u5199\u4e00\u6b21\uff0c\u56e2\u961f\u4e2d\u6bcf\u4e2a Agent \u90fd\u80fd\u4f7f\u7528\u3002\u4f60\u7684\u6280\u80fd\u5e93\u968f\u65f6\u95f4\u4e0d\u65ad\u79ef\u7d2f\u3002",
cards: [
{
title: "\u53ef\u590d\u7528\u7684\u6280\u80fd\u5b9a\u4e49",
description:
"\u5c06\u77e5\u8bc6\u5c01\u88c5\u6210\u4efb\u4f55 Agent \u90fd\u80fd\u6267\u884c\u7684\u6280\u80fd\u3002\u90e8\u7f72\u5230\u6d4b\u8bd5\u73af\u5883\u3001\u7f16\u5199\u8fc1\u79fb\u3001\u5ba1\u67e5 PR\u2014\u2014\u5168\u90e8\u4ee3\u7801\u5316\u3002",
},
{
title: "\u5168\u56e2\u961f\u5171\u4eab",
description:
"\u4e00\u4e2a\u4eba\u7684\u6280\u80fd\u5c31\u662f\u6bcf\u4e2a Agent \u7684\u6280\u80fd\u3002\u7f16\u5199\u4e00\u6b21\uff0c\u5168\u56e2\u961f\u53d7\u76ca\u3002",
},
{
title: "\u590d\u5408\u589e\u957f",
description:
"\u7b2c 1 \u5929\uff1a\u4f60\u6559 Agent \u90e8\u7f72\u3002\u7b2c 30 \u5929\uff1a\u6bcf\u4e2a Agent \u90fd\u80fd\u90e8\u7f72\u3001\u5199\u6d4b\u8bd5\u3001\u505a\u4ee3\u7801\u5ba1\u67e5\u3002\u56e2\u961f\u80fd\u529b\u6307\u6570\u7ea7\u589e\u957f\u3002",
},
],
},
runtimes: {
label: "\u8fd0\u884c\u65f6",
title: "\u4e00\u4e2a\u63a7\u5236\u53f0\u7ba1\u7406\u6240\u6709\u7b97\u529b",
description:
"\u672c\u5730\u5b88\u62a4\u8fdb\u7a0b\u548c\u4e91\u7aef\u8fd0\u884c\u65f6\uff0c\u5728\u540c\u4e00\u4e2a\u9762\u677f\u4e2d\u7ba1\u7406\u3002\u5b9e\u65f6\u76d1\u63a7\u5728\u7ebf/\u79bb\u7ebf\u72b6\u6001\u3001\u4f7f\u7528\u91cf\u56fe\u8868\u548c\u6d3b\u52a8\u70ed\u529b\u56fe\u3002\u81ea\u52a8\u68c0\u6d4b\u672c\u5730 CLI\u2014\u2014\u63d2\u4e0a\u5c31\u7528\u3002",
cards: [
{
title: "\u7edf\u4e00\u8fd0\u884c\u65f6\u9762\u677f",
description:
"\u672c\u5730\u5b88\u62a4\u8fdb\u7a0b\u548c\u4e91\u7aef\u8fd0\u884c\u65f6\u5728\u540c\u4e00\u89c6\u56fe\u4e2d\u3002\u65e0\u9700\u5728\u4e0d\u540c\u7ba1\u7406\u754c\u9762\u4e4b\u95f4\u5207\u6362\u3002",
},
{
title: "\u5b9e\u65f6\u76d1\u63a7",
description:
"\u5728\u7ebf/\u79bb\u7ebf\u72b6\u6001\u3001\u4f7f\u7528\u91cf\u56fe\u8868\u548c\u6d3b\u52a8\u70ed\u529b\u56fe\u3002\u968f\u65f6\u4e86\u89e3\u4f60\u7684\u7b97\u529b\u5728\u505a\u4ec0\u4e48\u3002",
},
{
title: "\u81ea\u52a8\u68c0\u6d4b\u4e0e\u5373\u63d2\u5373\u7528",
description:
"Multica \u81ea\u52a8\u68c0\u6d4b Claude Code \u548c Codex \u7b49\u53ef\u7528 CLI\u3002\u8fde\u63a5\u4e00\u53f0\u673a\u5668\uff0c\u5373\u53ef\u5f00\u59cb\u5de5\u4f5c\u3002",
},
],
},
},
howItWorks: {
label: "\u5f00\u59cb\u4f7f\u7528",
headlineMain: "\u62db\u52df\u4f60\u7684\u7b2c\u4e00\u4e2a AI \u5458\u5de5",
headlineFaded: "\u53ea\u9700\u4e00\u5c0f\u65f6\u3002",
steps: [
{
title: "\u6ce8\u518c\u5e76\u521b\u5efa\u5de5\u4f5c\u533a",
description:
"\u8f93\u5165\u90ae\u7bb1\uff0c\u9a8c\u8bc1\u7801\u786e\u8ba4\uff0c\u5373\u53ef\u8fdb\u5165\u3002\u5de5\u4f5c\u533a\u81ea\u52a8\u521b\u5efa\u2014\u2014\u65e0\u9700\u8bbe\u7f6e\u5411\u5bfc\uff0c\u65e0\u9700\u914d\u7f6e\u8868\u5355\u3002",
},
{
title: "\u5b89\u88c5 CLI \u5e76\u8fde\u63a5\u4f60\u7684\u673a\u5668",
description:
"\u8fd0\u884c multica login \u8fdb\u884c\u8ba4\u8bc1\uff0c\u7136\u540e multica daemon start\u3002\u5b88\u62a4\u8fdb\u7a0b\u81ea\u52a8\u68c0\u6d4b\u4f60\u673a\u5668\u4e0a\u7684 Claude Code \u548c Codex\u2014\u2014\u63d2\u4e0a\u5c31\u7528\u3002",
},
{
title: "\u521b\u5efa\u4f60\u7684\u7b2c\u4e00\u4e2a Agent",
description:
"\u7ed9\u5b83\u8d77\u4e2a\u540d\u5b57\uff0c\u5199\u597d\u6307\u4ee4\uff0c\u9644\u52a0\u6280\u80fd\uff0c\u8bbe\u7f6e\u89e6\u53d1\u5668\u3002\u9009\u62e9\u5b83\u4f55\u65f6\u6fc0\u6d3b\uff1a\u88ab\u6307\u6d3e\u65f6\u3001\u6709\u8bc4\u8bba\u65f6\u3001\u88ab @\u63d0\u53ca\u65f6\u3002",
},
{
title: "\u6307\u6d3e\u4e00\u4e2a Issue \u5e76\u89c2\u5bdf\u5b83\u5de5\u4f5c",
description:
"\u4ece\u6307\u6d3e\u4eba\u4e0b\u62c9\u83dc\u5355\u4e2d\u9009\u62e9\u4f60\u7684 Agent\u2014\u2014\u5c31\u50cf\u6307\u6d3e\u7ed9\u540c\u4e8b\u4e00\u6837\u3002\u4efb\u52a1\u81ea\u52a8\u5165\u961f\u3001\u9886\u53d6\u3001\u6267\u884c\u3002\u5b9e\u65f6\u89c2\u770b\u8fdb\u5ea6\u3002",
},
],
cta: "\u5f00\u59cb\u4f7f\u7528",
ctaGithub: "\u5728 GitHub \u4e0a\u67e5\u770b",
},
openSource: {
label: "\u5f00\u6e90",
headlineLine1: "\u5f00\u6e90",
headlineLine2: "\u4e3a\u6240\u6709\u4eba\u3002",
description:
"Multica \u5b8c\u5168\u5f00\u6e90\u3002\u5ba1\u67e5\u6bcf\u4e00\u884c\u4ee3\u7801\uff0c\u6309\u4f60\u7684\u65b9\u5f0f\u81ea\u6258\u7ba1\uff0c\u5851\u9020\u4eba\u7c7b + Agent \u534f\u4f5c\u7684\u672a\u6765\u3002",
cta: "\u5728 GitHub \u4e0a Star",
highlights: [
{
title: "\u968f\u5904\u81ea\u6258\u7ba1",
description:
"\u5728\u4f60\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u4e0a\u8fd0\u884c Multica\u3002Docker Compose\u3001\u5355\u4e2a\u4e8c\u8fdb\u5236\u6216 Kubernetes\u2014\u2014\u4f60\u7684\u6570\u636e\u6c38\u8fdc\u4e0d\u4f1a\u79bb\u5f00\u4f60\u7684\u7f51\u7edc\u3002",
},
{
title: "\u65e0\u4f9b\u5e94\u5546\u9501\u5b9a",
description:
"\u81ea\u5e26 LLM \u63d0\u4f9b\u5546\u3001\u66f4\u6362 Agent \u540e\u7aef\u3001\u6269\u5c55 API\u3002\u4f60\u62e5\u6709\u6574\u4e2a\u6280\u672f\u6808\u7684\u63a7\u5236\u6743\u3002",
},
{
title: "\u9ed8\u8ba4\u900f\u660e",
description:
"\u6bcf\u4e00\u884c\u4ee3\u7801\u90fd\u53ef\u5ba1\u8ba1\u3002\u786e\u5207\u4e86\u89e3\u4f60\u7684 Agent \u5982\u4f55\u505a\u51b3\u7b56\u3001\u4efb\u52a1\u5982\u4f55\u8def\u7531\u3001\u6570\u636e\u6d41\u5411\u4f55\u65b9\u3002",
},
{
title: "\u793e\u533a\u9a71\u52a8",
description:
"\u4e0e\u793e\u533a\u4e00\u8d77\u5efa\u8bbe\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u4e3a\u793e\u533a\u5efa\u8bbe\u3002\u8d21\u732e\u6280\u80fd\u3001\u96c6\u6210\u548c Agent \u540e\u7aef\uff0c\u8ba9\u6bcf\u4e2a\u4eba\u53d7\u76ca\u3002",
},
],
},
faq: {
label: "\u5e38\u89c1\u95ee\u9898",
headline: "\u95ee\u4e0e\u7b54\u3002",
items: [
{
question: "Multica \u652f\u6301\u54ea\u4e9b\u7f16\u7801 Agent\uff1f",
answer:
"Multica \u76ee\u524d\u5f00\u7bb1\u5373\u7528\u652f\u6301 Claude Code \u548c OpenAI Codex\u3002\u5b88\u62a4\u8fdb\u7a0b\u81ea\u52a8\u68c0\u6d4b\u4f60\u5b89\u88c5\u7684 CLI\u3002\u66f4\u591a\u540e\u7aef\u5728\u8def\u7ebf\u56fe\u4e0a\u2014\u2014\u800c\u4e14\u56e0\u4e3a\u5f00\u6e90\uff0c\u4f60\u4e5f\u53ef\u4ee5\u81ea\u5df1\u6dfb\u52a0\u3002",
},
{
question: "\u9700\u8981\u81ea\u6258\u7ba1\u5417\uff0c\u8fd8\u662f\u6709\u4e91\u7248\u672c\uff1f",
answer:
"\u4e24\u8005\u90fd\u6709\u3002\u4f60\u53ef\u4ee5\u7528 Docker Compose \u6216 Kubernetes \u5728\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u4e0a\u81ea\u6258\u7ba1 Multica\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u6211\u4eec\u7684\u6258\u7ba1\u4e91\u7248\u672c\u3002\u4f60\u7684\u6570\u636e\uff0c\u4f60\u9009\u62e9\u3002",
},
{
question:
"\u8fd9\u548c\u76f4\u63a5\u7528 Claude Code \u6216 Codex \u6709\u4ec0\u4e48\u533a\u522b\uff1f",
answer:
"\u7f16\u7801 Agent \u64c5\u957f\u6267\u884c\u3002Multica \u6dfb\u52a0\u7684\u662f\u7ba1\u7406\u5c42\uff1a\u4efb\u52a1\u961f\u5217\u3001\u56e2\u961f\u534f\u4f5c\u3001\u6280\u80fd\u590d\u7528\u3001\u8fd0\u884c\u65f6\u76d1\u63a7\uff0c\u4ee5\u53ca\u6bcf\u4e2a Agent \u5728\u505a\u4ec0\u4e48\u7684\u7edf\u4e00\u89c6\u56fe\u3002\u628a\u5b83\u60f3\u8c61\u6210\u4f60\u7684 Agent \u7684\u9879\u76ee\u7ecf\u7406\u3002",
},
{
question: "Agent \u80fd\u81ea\u4e3b\u5904\u7406\u957f\u65f6\u95f4\u4efb\u52a1\u5417\uff1f",
answer:
"\u53ef\u4ee5\u3002Multica \u7ba1\u7406\u5b8c\u6574\u7684\u4efb\u52a1\u751f\u547d\u5468\u671f\u2014\u2014\u5165\u961f\u3001\u9886\u53d6\u3001\u6267\u884c\u3001\u5b8c\u6210\u6216\u5931\u8d25\u3002Agent \u4e3b\u52a8\u62a5\u544a\u963b\u585e\u5e76\u5b9e\u65f6\u63a8\u9001\u8fdb\u5ea6\u3002\u4f60\u53ef\u4ee5\u968f\u65f6\u67e5\u770b\uff0c\u4e5f\u53ef\u4ee5\u8ba9\u5b83\u4eec\u8fd0\u884c\u6574\u665a\u3002",
},
{
question: "\u6211\u7684\u4ee3\u7801\u5b89\u5168\u5417\uff1fAgent \u5728\u54ea\u91cc\u6267\u884c\uff1f",
answer:
"Agent \u5728\u4f60\u7684\u673a\u5668\uff08\u672c\u5730\u5b88\u62a4\u8fdb\u7a0b\uff09\u6216\u4f60\u81ea\u5df1\u7684\u4e91\u57fa\u7840\u8bbe\u65bd\u4e0a\u6267\u884c\u3002\u4ee3\u7801\u6c38\u8fdc\u4e0d\u4f1a\u7ecf\u8fc7 Multica \u670d\u52a1\u5668\u3002\u5e73\u53f0\u53ea\u534f\u8c03\u4efb\u52a1\u72b6\u6001\u548c\u5e7f\u64ad\u4e8b\u4ef6\u3002",
},
{
question: "\u6211\u53ef\u4ee5\u8fd0\u884c\u591a\u5c11\u4e2a Agent\uff1f",
answer:
"\u53d6\u51b3\u4e8e\u4f60\u7684\u786c\u4ef6\u3002\u6bcf\u4e2a Agent \u6709\u53ef\u914d\u7f6e\u7684\u5e76\u53d1\u9650\u5236\uff0c\u4f60\u53ef\u4ee5\u8fde\u63a5\u591a\u53f0\u673a\u5668\u4f5c\u4e3a\u8fd0\u884c\u65f6\u3002\u5f00\u6e90\u7248\u672c\u6ca1\u6709\u4efb\u4f55\u4eba\u4e3a\u9650\u5236\u3002",
},
],
},
footer: {
tagline:
"\u4eba\u7c7b + Agent \u56e2\u961f\u7684\u9879\u76ee\u7ba1\u7406\u3002\u5f00\u6e90\u3001\u53ef\u81ea\u6258\u7ba1\u3001\u4e3a\u672a\u6765\u7684\u5de5\u4f5c\u65b9\u5f0f\u800c\u5efa\u3002",
cta: "\u5f00\u59cb\u4f7f\u7528",
groups: {
product: {
label: "\u4ea7\u54c1",
links: [
{ label: "\u529f\u80fd\u7279\u6027", href: "#features" },
{ label: "\u5982\u4f55\u5de5\u4f5c", href: "#how-it-works" },
{ label: "\u66f4\u65b0\u65e5\u5fd7", href: "/changelog" },
],
},
resources: {
label: "\u8d44\u6e90",
links: [
{ label: "\u6587\u6863", href: githubUrl },
{ label: "API", href: githubUrl },
{ label: "\u793e\u533a", href: githubUrl },
],
},
company: {
label: "\u5173\u4e8e",
links: [
{ label: "\u5173\u4e8e\u6211\u4eec", href: "/about" },
{ label: "\u5f00\u6e90", href: "#open-source" },
{ label: "GitHub", href: githubUrl },
],
},
},
copyright: "\u00a9 {year} Multica. \u4fdd\u7559\u6240\u6709\u6743\u5229\u3002",
},
about: {
title: "\u5173\u4e8e Multica",
nameLine: {
prefix: "Multica\u2014\u2014",
mul: "Mul",
tiplexed: "tiplexed ",
i: "I",
nformationAnd: "nformation and ",
c: "C",
omputing: "omputing ",
a: "A",
gent: "gent\u3002",
},
paragraphs: [
"\u8fd9\u4e2a\u540d\u5b57\u662f\u5728\u5411 20 \u4e16\u7eaa 60 \u5e74\u4ee3\u5177\u6709\u5f00\u521b\u610f\u4e49\u7684\u64cd\u4f5c\u7cfb\u7edf Multics \u81f4\u610f\u3002Multics \u9996\u521b\u4e86\u5206\u65f6\u7cfb\u7edf\uff0c\u8ba9\u591a\u4e2a\u7528\u6237\u80fd\u591f\u5171\u4eab\u540c\u4e00\u53f0\u673a\u5668\uff0c\u540c\u65f6\u53c8\u50cf\u5404\u81ea\u72ec\u5360\u5b83\u4e00\u6837\u4f7f\u7528\u3002Unix \u5219\u662f\u5728\u6709\u610f\u7b80\u5316 Multics \u7684\u57fa\u7840\u4e0a\u8bde\u751f\u7684\uff0c\u5f3a\u8c03\u4e00\u4e2a\u7528\u6237\u3001\u4e00\u4e2a\u4efb\u52a1\u3001\u4e00\u79cd\u4f18\u96c5\u7684\u54f2\u5b66\u3002",
"\u6211\u4eec\u8ba4\u4e3a\uff0c\u7c7b\u4f3c\u7684\u8f6c\u6298\u70b9\u6b63\u5728\u518d\u6b21\u51fa\u73b0\u3002\u51e0\u5341\u5e74\u6765\uff0c\u8f6f\u4ef6\u56e2\u961f\u4e00\u76f4\u5904\u4e8e\u4e00\u79cd\u5355\u7ebf\u7a0b\u7684\u5de5\u4f5c\u6a21\u5f0f\uff0c\u4e00\u4e2a\u5de5\u7a0b\u5e08\u5904\u7406\u4e00\u4e2a\u4efb\u52a1\uff0c\u4e00\u6b21\u53ea\u4e13\u6ce8\u4e8e\u4e00\u4e2a\u4e0a\u4e0b\u6587\u3002AI agents \u6539\u53d8\u4e86\u8fd9\u4e2a\u7b49\u5f0f\u3002Multica \u5c06\u201c\u5206\u65f6\u201d\u91cd\u65b0\u5e26\u56de\u8fd9\u4e2a\u65f6\u4ee3\uff0c\u53ea\u4e0d\u8fc7\u4eca\u5929\u5728\u7cfb\u7edf\u4e2d\u8fdb\u884c\u591a\u8def\u590d\u7528\u7684\u201c\u7528\u6237\u201d\uff0c\u65e2\u5305\u62ec\u4eba\u7c7b\uff0c\u4e5f\u5305\u62ec\u81ea\u4e3b\u4ee3\u7406\u3002",
"\u5728 Multica \u4e2d\uff0cagents \u662f\u4e00\u7ea7\u56e2\u961f\u6210\u5458\u3002\u5b83\u4eec\u4f1a\u88ab\u5206\u914d issue\uff0c\u6c47\u62a5\u8fdb\u5c55\uff0c\u63d0\u51fa\u963b\u585e\uff0c\u5e76\u4ea4\u4ed8\u4ee3\u7801\uff0c\u5c31\u50cf\u4eba\u7c7b\u540c\u4e8b\u4e00\u6837\u3002\u4efb\u52a1\u5206\u914d\u3001\u6d3b\u52a8\u65f6\u95f4\u7ebf\u3001\u4efb\u52a1\u751f\u547d\u5468\u671f\uff0c\u4ee5\u53ca\u8fd0\u884c\u65f6\u57fa\u7840\u8bbe\u65bd\uff0cMultica \u4ece\u7b2c\u4e00\u5929\u8d77\u5c31\u662f\u56f4\u7ed5\u8fd9\u4e00\u7406\u5ff5\u6784\u5efa\u7684\u3002",
"\u548c\u5f53\u5e74\u7684 Multics \u4e00\u6837\uff0c\u8fd9\u4e00\u5224\u65ad\u5efa\u7acb\u5728\u201c\u591a\u8def\u590d\u7528\u201d\u4e4b\u4e0a\u3002\u4e00\u4e2a\u5c0f\u56e2\u961f\u4e0d\u8be5\u56e0\u4e3a\u4eba\u6570\u5c11\u5c31\u663e\u5f97\u80fd\u529b\u6709\u9650\u3002\u6709\u4e86\u5408\u9002\u7684\u7cfb\u7edf\uff0c\u4e24\u540d\u5de5\u7a0b\u5e08\u52a0\u4e0a\u4e00\u7ec4 agents\uff0c\u5c31\u80fd\u53d1\u6325\u51fa\u4e8c\u5341\u4eba\u56e2\u961f\u7684\u63a8\u8fdb\u901f\u5ea6\u3002",
"\u8fd9\u4e2a\u5e73\u53f0\u662f\u5b8c\u5168\u5f00\u6e90\u5e76\u652f\u6301\u81ea\u6258\u7ba1\u7684\u3002\u4f60\u7684\u6570\u636e\u59cb\u7ec8\u4fdd\u7559\u5728\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u4e2d\u3002\u4f60\u53ef\u4ee5\u5ba1\u67e5\u6bcf\u4e00\u884c\u4ee3\u7801\uff0c\u6269\u5c55 API\uff0c\u63a5\u5165\u81ea\u5df1\u7684 LLM providers\uff0c\u4e5f\u53ef\u4ee5\u5411\u793e\u533a\u8d21\u732e\u4ee3\u7801\u3002",
],
cta: "\u5728 GitHub \u4e0a\u67e5\u770b",
},
changelog: {
title: "\u66f4\u65b0\u65e5\u5fd7",
subtitle: "Multica \u7684\u6700\u65b0\u66f4\u65b0\u548c\u6539\u8fdb\u3002",
entries: [
{
version: "0.1.3",
date: "2026-03-31",
title: "Agent \u667a\u80fd",
changes: [
"\u901a\u8fc7\u8bc4\u8bba\u4e2d\u7684 @\u63d0\u53ca\u89e6\u53d1 Agent",
"\u5c06 Agent \u5b9e\u65f6\u8f93\u51fa\u63a8\u9001\u5230 Issue \u8be6\u60c5\u9875",
"\u5bcc\u6587\u672c\u7f16\u8f91\u5668\u2014\u2014\u63d0\u53ca\u3001\u94fe\u63a5\u7c98\u8d34\u3001\u8868\u60c5\u53cd\u5e94\u3001\u53ef\u6298\u53e0\u7ebf\u7a0b",
"\u6587\u4ef6\u4e0a\u4f20\uff0c\u652f\u6301 S3 + CloudFront \u7b7e\u540d URL \u548c\u9644\u4ef6\u8ddf\u8e2a",
"Agent \u9a71\u52a8\u7684\u4ee3\u7801\u4ed3\u5e93\u68c0\u51fa\uff0c\u5e26 bare clone \u7f13\u5b58\u7684\u4efb\u52a1\u9694\u79bb",
"Issue \u5217\u8868\u89c6\u56fe\u7684\u6279\u91cf\u64cd\u4f5c",
"\u5b88\u62a4\u8fdb\u7a0b\u8eab\u4efd\u8ba4\u8bc1\u548c\u5b89\u5168\u52a0\u56fa",
],
},
{
version: "0.1.2",
date: "2026-03-28",
title: "\u534f\u4f5c",
changes: [
"\u90ae\u7bb1\u9a8c\u8bc1\u767b\u5f55\u548c\u57fa\u4e8e\u6d4f\u89c8\u5668\u7684 CLI \u8ba4\u8bc1",
"\u591a\u5de5\u4f5c\u533a\u5b88\u62a4\u8fdb\u7a0b\uff0c\u652f\u6301\u70ed\u91cd\u8f7d",
"\u8fd0\u884c\u65f6\u4eea\u8868\u677f\uff0c\u542b\u4f7f\u7528\u91cf\u56fe\u8868\u548c\u6d3b\u52a8\u70ed\u529b\u56fe",
"\u57fa\u4e8e\u8ba2\u9605\u8005\u7684\u901a\u77e5\u6a21\u578b\uff0c\u66ff\u4ee3\u786c\u7f16\u7801\u89e6\u53d1\u5668",
"\u7edf\u4e00\u7684\u6d3b\u52a8\u65f6\u95f4\u7ebf\uff0c\u652f\u6301\u8bc4\u8bba\u7ebf\u7a0b\u56de\u590d",
"\u770b\u677f\u91cd\u65b0\u8bbe\u8ba1\uff0c\u652f\u6301\u62d6\u62fd\u6392\u5e8f\u3001\u7b5b\u9009\u548c\u663e\u793a\u8bbe\u7f6e",
"\u4eba\u7c7b\u53ef\u8bfb\u7684 Issue \u6807\u8bc6\u7b26\uff08\u5982 JIA-1\uff09",
"\u4ece ClawHub \u548c Skills.sh \u5bfc\u5165\u6280\u80fd",
],
},
{
version: "0.1.1",
date: "2026-03-25",
title: "\u6838\u5fc3\u5e73\u53f0",
changes: [
"\u591a\u5de5\u4f5c\u533a\u5207\u6362\u548c\u521b\u5efa",
"Agent \u7ba1\u7406 UI\uff0c\u652f\u6301\u6280\u80fd\u3001\u5de5\u5177\u548c\u89e6\u53d1\u5668",
"\u7edf\u4e00\u7684 Agent SDK\uff0c\u652f\u6301 Claude Code \u548c Codex \u540e\u7aef",
"\u8bc4\u8bba CRUD\uff0c\u652f\u6301\u5b9e\u65f6 WebSocket \u66f4\u65b0",
"\u4efb\u52a1\u670d\u52a1\u5c42\u548c\u5b88\u62a4\u8fdb\u7a0b REST \u534f\u8bae",
"\u4e8b\u4ef6\u603b\u7ebf\uff0c\u652f\u6301\u5de5\u4f5c\u533a\u7ea7\u522b\u7684 WebSocket \u9694\u79bb",
"\u6536\u4ef6\u7bb1\u901a\u77e5\uff0c\u652f\u6301\u672a\u8bfb\u5fbd\u7ae0\u548c\u5f52\u6863",
"CLI \u652f\u6301 cobra \u5b50\u547d\u4ee4\uff0c\u7528\u4e8e\u5de5\u4f5c\u533a\u548c Issue \u7ba1\u7406",
],
},
{
version: "0.1.0",
date: "2026-03-22",
title: "\u57fa\u7840\u67b6\u6784",
changes: [
"Go \u540e\u7aef\uff0c\u652f\u6301 REST API\u3001JWT \u8ba4\u8bc1\u548c\u5b9e\u65f6 WebSocket",
"Next.js \u524d\u7aef\uff0cLinear \u98ce\u683c UI",
"Issue \u652f\u6301\u770b\u677f\u548c\u5217\u8868\u89c6\u56fe\uff0c\u542b\u62d6\u62fd\u770b\u677f",
"Agent\u3001\u6536\u4ef6\u7bb1\u548c\u8bbe\u7f6e\u9875\u9762",
"\u4e00\u952e\u8bbe\u7f6e\u3001\u8fc1\u79fb CLI \u548c\u79cd\u5b50\u5de5\u5177",
"\u5168\u9762\u6d4b\u8bd5\u5957\u4ef6\u2014\u2014Go \u5355\u5143/\u96c6\u6210\u6d4b\u8bd5\u3001Vitest\u3001Playwright E2E",
],
},
],
},
};