Melso Docs

Conventions

Single source of truth for code naming, i18n translation glossary, and Chinese voice guide.

This page is the single source of truth for code naming, the i18n translation glossary, and the Chinese voice guide. Anything that used to live in packages/views/locales/glossary.md or in scattered comments now lives here.

If you write Melso code, change a translation, or write Chinese product copy, this is the page to reference.


1. Code naming

Routes

Pre-workspace routes (the routes that exist before the user is in a workspace) MUST use either a single word or the /{noun}/{verb} pattern.

  • /login, /inbox, /workspaces/new
  • /new-workspace, /create-team, /accept-invite

Hyphenated word groups at the root collide with user-chosen workspace slugs and force endless reserved-slug audits. Reserving the noun (workspaces) automatically protects the entire /workspaces/* subtree.

Workspace-scoped routes

Always live under /{slug}/{section}/{slug}/issues, /{slug}/agents, /{slug}/settings. Never duplicate workspace routing logic; use useNavigation().push() from shared code, never framework-specific link APIs.

Packages and modules

The monorepo enforces strict package boundaries:

PackageMay depend onMust NOT depend on
packages/corenothing app-specificreact-dom, localStorage, process.env, next/*, UI libraries
packages/uinothing@multica/core, business logic
packages/viewscore/, ui/next/*, react-router-dom, stores
apps/web/platform/next/*other apps
apps/desktop/.../platform/react-router-dom, electronother apps
apps/mobile/types and pure functions from @multica/coreWeb/Desktop React pages, stores, and platform implementations

If logic appears in both apps, it MUST be extracted to a shared package. There are no exceptions for "small" duplication. Mobile owns a separate UI, data layer, and release process; it shares only types and pure functions.

Files and components

  • Files: kebab-case.tsx / kebab-case.ts (e.g. agent-row-actions.tsx)
  • Components: PascalCase (e.g. AgentRowActions)
  • Hooks: useCamelCase (e.g. useWorkspaceId)
  • Tests: colocated as <file>.test.ts(x)
  • Stores (Zustand): <feature>-store.ts, exported as use<Feature>Store

Database (Go + sqlc)

  • Tables: snake_case singular (user, workspace, agent_runtime)
  • Columns: snake_case (workspace_id, created_at, last_seen_at)
  • Foreign keys: <table>_id
  • Booleans: is_<state> or <state>_at (timestamp form preferred for state changes)
  • Migration files: NNN_descriptive_name.up.sql + .down.sql — always provide both directions
  • Do not create database foreign keys or use cascade deletes or updates; enforce relationships and cleanup in the application layer.
  • Every index must use CREATE INDEX CONCURRENTLY or CREATE UNIQUE INDEX CONCURRENTLY, with each concurrent index in its own single-statement migration file.

Go

  • Standard gofmt + go vet. No exceptions.
  • Handler files mirror domain: agent.go, auth.go, runtime.go
  • Tests: <file>_test.go colocated
  • For UUID parsing in handlers, follow the rule in the root CLAUDE.mdparseUUIDOrBadRequest for boundary input, parseUUID (panicking) for trusted round-trips, never util.ParseUUID directly without checking the error.

TypeScript

  • API responses on the wire are snake_case; the api client converts to camelCase at the boundary. Inside TS code, always camelCase.
  • Types: PascalCase (Issue, AgentRuntime); never IPrefix, never _t suffix.
  • Enums: prefer string literal unions; reserve enum for runtime-iterable cases.
  • TanStack Query keys: factory functions in <feature>/queries.ts, e.g. issueKeys.detail(id).

API boundaries

  • Parse network responses with parseWithFallback and zod schemas from packages/core/api/schema.ts; do not cast them directly with as T.
  • When adding or changing an endpoint, update its schema and cover missing or malformed fields in tests.
  • Downstream UI must provide defaults for optional fields, and every switch over a server enum must include a default branch.
  • An installed Desktop client may connect to a newer backend; never assume that frontend and backend versions always match.

Runtime display names

AgentRuntime.name is the daemon's raw technical name (e.g. Codex (host)); the user's alias lives in custom_name. User-visible copy must never render runtime.name directly — use the shared helpers so aliases and provider stay consistent (MUL-5248, #5260):

  • Standalone runtime label (lists, chips, confirm dialogs, document titles): runtimeDisplayLabel(runtime) → alias + provider, falling back to the daemon name.
  • When a provider icon/text already sits beside it: runtimeDisplayName(runtime) → alias only, no duplicated provider.
  • Inside a machine group: machine header uses machine.title, child rows use runtimeRowLabel(runtime, machine.title).
  • Runtime selectors group by machine via buildRuntimeMachines; do not build a flat list of raw names.

Raw runtime.name is allowed only for internal identity — hostname parsing, grouping, search haystacks, and protocol payloads — never for JSX text, i18n params, <Select> labels, or window titles.

Issue keys

Every issue has a human-readable key like MUL-123: workspace issue_prefix (uppercase letters and digits, typically 3 chars, max 10) + sequence number. Workspace admins can change the prefix in Settings → General; changing it renumbers every existing issue, so external references that embed the old prefix (PR titles, branch names, links in docs and chat) stop resolving.

Comments in code

English only. The repo enforces this for both Go and TypeScript. If you find a Chinese comment in code, it's a bug — replace it.

Commit messages

Conventional format: feat(scope), fix(scope), refactor(scope), docs, test(scope), chore(scope). Atomic commits grouped by intent.


2. i18n translation glossary

This is the mandatory glossary for every translation PR. It used to live at packages/views/locales/glossary.md; that file is now a stub pointing here.

The core distinction: everyday noun vs Melso-specific term

Melso's product nouns split into two categories:

  • Everyday noun — the word a user would say out loud for it. Translate fully, whether or not it is a database entity: issue → 任务, workspace → 工作区, project → 项目.
  • Melso-specific term — a concept no local word carries (skill), or a schema-level identifier a user may have to type or match (todo, in_progress, task_id). Render as lowercase English so it reads like a type name.

The Chinese pages under apps/docs/content/docs/*.zh.mdx are the de facto voice standard for everything else on this page. They still carry the old English issue in prose and are being swept separately — follow the table below, not those pages, for this term.

issue is the product's task — translate it

issue is the English product name for the thing a user files and an agent works on. In every other locale it is the everyday word for "task":

Entityenzh-Hansjako
the filed unit of work (issue)Issue任务タスク태스크
one agent execution run (task)Tasktask作業작업

Both nouns are user-visible and they are not the same thing — an issue can carry many runs. Never let one locale spell both with the same word, which is why the run keeps a visually distinct form in each locale.

What does not move:

  • API / DB fields stay issue / task / skill everywhere: issue_status, task_id, skill_uuid.
  • Code references and literal commands stay English: melso issue ..., the /issue Slack and Lark slash command.
  • skill keeps lowercase English in Chinese text — a Melso-specific concept with no established Chinese term; titles may capitalize as Skills.
  • issue in the "problem" sense (runtime health) is a plain noun, not the entity: {{count}} issues on a machine card is {{count}} 个异常, not 任务.

Why issue is translated while skill is not: users file and read issues all day, and "issue" has no meaning in Chinese, Japanese, or Korean outside of dev jargon. The everyday task word is what people already say for this. skill is a Melso-specific concept where no local word carries the meaning.

Other product nouns follow the same "translate what has a settled local word" test:

  • project → "项目": settled mainstream Chinese word. Feishu / Tower / Teambition / PingCode / GitHub Projects — every Chinese product translates it. No product keeps project in Chinese context.
  • autopilot → "自动化": in Chinese, "autopilot" associates with Tesla's "自动驾驶" and doesn't match what the feature does (run tasks on a schedule). Notion and Feishu both use "自动化"; that's the industry consensus.

Don't translate — brands and acronyms

CategoryTerms
BrandsMelso, GitHub, Slack, Google, Anthropic, OpenAI, Claude, Codex, Cursor, Linear, Jira
AcronymsAPI, CLI, URL, SDK, OAuth, JWT, SSO, WebSocket, HTTP, JSON, YAML, SQL

Translate fully — concepts

EnglishChinese
Workspace工作区
Agent智能体
Project项目
Autopilot自动化
Daemon守护进程
Runtime运行时
Inbox收件箱
Comment评论
Reply回复
Notifications通知
Member成员
Label标签
Settings设置
Onboarding上手引导

Translate fully — generic UI words

EnglishChinese
Invite / Invitation邀请
Search搜索
Email邮箱 (label) / 邮件 (action)
Password密码
Sign in / Log in登录
Sign up注册
Sign out / Log out退出登录
Save / Cancel / Delete保存 / 取消 / 删除
Confirm / Continue / Back确认 / 继续 / 返回
Edit / New / Create / Add编辑 / 新建 / 创建 / 添加
Remove / Send / Open / Close移除 / 发送 / 打开 / 关闭
Preview / Download / Upload预览 / 下载 / 上传
Done / Loading...完成 / 加载中...
Profile / Account / Appearance个人资料 / 账号 / 外观
Theme / Language主题 / 语言
Light / Dark / System浅色 / 深色 / 跟随系统
Active / Archived活跃 (or 启用) / 已归档
Status / Priority状态 / 优先级
Assignee / Reporter负责人 / 报告人
Description / Title描述 / 标题
Date / Time日期 / 时间
Today / Yesterday / Tomorrow今天 / 昨天 / 明天
Empty / Failed / Success空 / 失败 / 成功
Error / Warning错误 / 警告

Roles and status enums (lowercase English, not translated)

These are schema-level identifiers; render as lowercase English even in Chinese context.

  • Roles: owner / admin / member
  • Issue status: backlog / todo / in_progress / in_review / done / blocked / cancelled

In UI, surface them in English (optionally code-style wrapped):

  • "你需要 owner 权限"
  • "已切换到 in_progress"

Word combination rules

Always put a single space between an English word (entity / brand / acronym) and surrounding Chinese:

  • "Create new issue" → "新建任务"(任务 is Chinese, so no space)
  • "Assign to agent" → "分配给智能体"
  • "Configure runtime" → "配置运行时"
  • "Stop daemon" → "停止守护进程"

Plurals and counts

i18next uses _one / _other; Chinese has no grammatical number, only fill _other.

// en/issues.json
{
  "issue_count_one": "{{count}} issue",
  "issue_count_other": "{{count}} issues"
}

// zh-Hans/issues.json
{
  "issue_count_other": "{{count}} 个任务"
}

Common count formats:

  • {{count}} issues{{count}} 个任务
  • {{count}} agents{{count}} 个智能体
  • {{count}} workspaces{{count}} 个工作区
  • {{count}} comments{{count}} 条评论
  • {{count}} members{{count}} 位成员
  • {{count}} skills{{count}} 个 skill

Interpolation

Use {{var}}. Chinese translations may reorder for natural sentence flow.

// en
{ "welcome_message": "Welcome back, {{name}}!" }

// zh-Hans
{ "welcome_message": "欢迎回来,{{name}}!" }

Translation key naming

Three-level nesting: feature.component.action.

{
  "feature_or_component": {
    "subcomponent_or_section": {
      "action_or_label": "..."
    }
  }
}

Examples:

  • issues.toolbar.batch_update_success
  • issues.detail.comment_form.placeholder
  • inbox.empty.title
  • settings.preferences.language.title

Web-only / desktop-only copy

  • Shared copy: top level of the namespace JSON
  • Web-only: web section
  • Desktop-only: desktop section

See auth.json for the canonical example (the web section contains prefer_desktop / desktop_handoff.*).


3. Chinese voice and style

Punctuation

  • Full-width punctuation in Chinese: ,。:;!?
  • Quotes: straight double quotes "..." to match the English source. Do not use 「」 or curly quotes.
  • Ellipsis: three dots ... not the single character . Match the English source.
  • Mixed Chinese-English: a single space on each side of the English word (see Word combination rules).

Style principles

  • Concise and direct. Avoid translation-ese: "对于 X 来说"、"作为 X"、"我们的"。
  • Error messages: gentle but clear. "无法保存修改" beats "保存修改失败了!".
  • Buttons: verb first, 2–4 characters. "取消"、"保存修改"、"立即同步".
  • Tooltips: full short sentence. "复制链接到剪贴板".
  • Placeholders: example-style. "输入任务标题...".

Where to look when in doubt

When the glossary doesn't cover a term, look at:

  1. apps/docs/content/docs/*.zh.mdx — the de facto Chinese voice standard, 20+ pages of consistent translation
  2. packages/views/locales/zh-Hans/auth.json and editor.json — JSON structure + selector API patterns
  3. packages/views/auth/login-page.tsx — component-level selector API call site
  4. packages/views/settings/components/preferences-tab.tsx — language switcher reference

Updating this page

If you change a rule here, also:

  1. Apply it in the relevant locale JSONs / CLAUDE.md / docs page
  2. Note the change in the PR description so reviewers know to look for downstream sweep

This page is the contract; nothing else overrides it.