AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
正在載入完整 README。 以下為已儲存的摘錄。
프로젝트는 리포·권한·토큰·Publish를, TranslationSurface는 포맷·적재 상태·키·번역을 소유한다. 여러 활성 표면도 비중첩 경로만 허용하고 프로젝트당 PR 하나로 보낸다. 번역 URL은 /projects/:slug/surfaces/:surfaceSlug/translations, 소스 관리는 /projects/:slug/sources다. 옛 번역 URL은 기본 표면으로, 옛 Locales 두 URL은 Sources 목록으로 이동한다. OWNER는 Sources에서 소스를 추가하고 기준 언어를 선언한다. EDITOR는 연결 정보를 제외한 상태를 읽는다. LNB는 Home → Sources → Translations → Members → Logs → Project settings(OWNER) 순서다. 동일 키·언어 코드가 표면마다 공존한다.檢視完整 README ↗
Translators never touch Git: they sign in, edit, and hit Publish.
push to the base branch (GitHub Actions / GitLab CI) or nightly
Repository ──────────────────────────────────────────────▶ Malmoi
decides which keys exist teammates edit values
▲ │
│ one pull request / merge request (Publish or nightly) │
└──────────────────────────────────────────────────────────┘
Connect a repository and Malmoi detects and loads its translation files. New commits come in nightly, or on every push with the generated workflow; Publish sends saved edits back as one pull request. The two sides are never merged — the repository decides which keys exist, Malmoi holds the values. GitLab.com works the same way, with a personal access token and a merge request.
A source tree and key list on one side, the selected key in every language on the other. Search covers key names, source text, and translations.
Publish lists each key × language change before writing anything, and never writes to the base branch — merging stays with your reviewers.
Logs records edits, syncs, and publishes — who did what, with translation values before and after — for the life of the project.
A generated GitHub Actions workflow (or GitLab CI job) brings new keys in on every push, flags translations whose source changed as Needs review, and shows where your code uses each key.
| Format | Example path |
|---|---|
| JSON catalog | src/locales/{locale}.json |
| YAML catalog | config/locales/{locale}.yml |
| Chrome extension messages | _locales/{locale}/messages.json |
| Code dictionary, one file per language | src/locales/{locale}.ts |
| Code dictionary, all languages in one file | src/i18n/namespaces/*.ts |
| Flutter ARB | lib/l10n/app_{locale}.arb |
| Apple strings file | ios/App/{locale}.lproj/Localizable.strings |
| Apple String Catalog | ios/App/Localizable.xcstrings |
| Android strings file | app/src/main/res/values-{locale}/strings.xml |
Publish keeps each file's layout — comments, blank lines, key order,
indentation, encoding — as far as the format allows. Plurals (ICU, .stringsdict,
Android <plurals>) are kept but not edited. One project can mix several
sources and formats. Format-specific rules — such as Android's base language
and inline tags — are in the format reference;
size caps are in Limits.
Malmoi is a pipeline between your repository and your team, not a translation platform. By design, it has no translation memory or machine/AI translation, no ICU plural editing, no approval workflows or fine-grained permissions, and no real-time co-editing, in-context editing, screenshots, or translator notes. If you need those, a platform such as Crowdin or Tolgee is a better fit.
Exports are deterministic. The same data and original files produce byte-identical files, so Publish commits only the files that actually changed.
On GitHub, commits come from the GitHub App, not from people, so a translator leaving the organization doesn't break the pipeline. GitLab writes as the person whose token the project uses.
More in docs/ARCHITECTURE.md (Korean).
Use mal-moi.com, or run the same app on one Linux server with Docker Compose
(app, PostgreSQL 17, a nightly scheduler, behind your HTTPS proxy). Every
release publishes ghcr.io/sinhyeokkang/malmoi:v<x.y.z>. You bring the OAuth
apps for sign-in, a Resend domain for invitations, and optionally a GitHub App
to connect GitHub repositories. Kubernetes, multiple instances, GitHub
Enterprise, and GitLab Self-Managed aren't supported.
Self-hosting guide →
mal-moi.com sends data only to GitHub, GitLab and Google (if you use them), Supabase (database, Tokyo), Vercel (hosting, pictures, cookieless page-view counts), and Resend (invitation emails). A self-hosted installation uses the operator's own server instead of Supabase and Vercel, and its privacy policy is the operator's own. Full policy →
nvm use # Node 24
pnpm install
cp .env.example .env.local # fill in the values
pnpm db:generate
pnpm dev
Commands and conventions are in CLAUDE.md (Korean, also the
agent instructions); product scope is in docs/PRODUCT.md.
The engineering docs and source comments are in Korean — the project is built
by one person, and that's the language it was thought in.
MIT © 2026 Sinhyeok Kang