Getting Started

Harness Integrations

The MCP server gives every host the same tools. What differs per host is enforcement: a model that knows about write_translations will still reach for its file editor under pressure, and nothing in the protocol stops it. Hosts with a hook system can stop it. Hosts without one get the rules as context, and CI stays the backstop.

Claude Code

The repository doubles as a plugin marketplace:

/plugin marketplace add fabkho/the-i18n-kit
/plugin install the-i18n-kit@the-i18n-kit

One plugin, four components:

ComponentWhat it does
MCP serverthe-i18n-kit over stdio via npx @the-i18n-kit/mcp@latest — the same server Set Up the MCP Server configures by hand
PreToolUse hookDenies Edit and Write on files inside a locale directory, and answers with the tools to use instead. One hand-edited locale silently drifts from its siblings; the tools keep every locale consistent
Stop hookRuns check before the agent finishes. Keys referenced in code but defined in no consumed layer render as raw keys in production, so findings block the stop with the key names and the agent fixes them in-session instead of leaving them for CI
SkillThe workflow as guidance: orient with discover, read before writing, write through tools, verify with find_undefined_keys

Both hooks decide by walking up from the working directory to the nearest .i18n-mcp.json or i18n-kit.config.*. No config file, no opinion: outside a kit project they exit silently, so the plugin is safe to keep enabled globally. They resolve the-i18n-cli from the project's node_modules first, then a global install, then npx — and on any infrastructure failure they allow rather than block.

Two environment variables switch the enforcement off when you mean to bypass it:

VariableEffect
I18N_KIT_ALLOW_DIRECT_EDITS=1The locale-file guard stands down
I18N_KIT_SKIP_CHECK=1The stop gate stands down

Status Line

Claude Code plugins cannot ship a status line, so coverage in the footer is one manual step. The plugin carries the script; point your user settings at it:

~/.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "bash /path/to/the-i18n-kit/integrations/claude-code/statusline/i18n-statusline.sh"
  }
}

It prints per-locale coverage — 🌐 de 100% · es 75% · fr 92% · 4 missing — cached for a minute per project, and prints nothing outside kit projects, so it composes with a status line you already have.

pi

pi install npm:@the-i18n-kit/pi

An extension rather than hooks: a widget by the editor that shows change, never state.

🌐 4 keys missing · es-ES 3 · fr-FR 1
🌐 ⠹ ▕██████░░░░░░▏ es-ES: batch 1/1 3/6
🌐 es-ES +3 · fr-FR +1 · ⚠ fr-FR dropped {count}
🌐 2 undefined keys · checkout.payNow, cart.empty

A finished run is reported from its own result rather than from the totals: which locales moved, which translation dropped a placeholder — a broken string in front of a user — and which locales were left alone because they are protected, since three fewer locales than you asked for reads as failure until it is named. After a turn that edited source, check runs: keys the code calls and no layer defines render raw in production, and the moment the edit lands is the cheapest moment to hear about them.

Coverage is also published as a host status — 🌐 4 missing, 🌐 ✓ — which hosts with a footer render there. That is the standing fact the widget will not keep on screen: a transient line suits change, a footer suits state, and each surface gets the half it is good at.

The same figure is readable in-process, so a theme or another extension can put it wherever that setup actually looks — an editor border, a tmux status line — without this package knowing anything about it.

Colours are the theme's own — warning while work is outstanding, success once it is done — so the widget matches whatever theme you run rather than introducing a palette. The bar tracks real progress notifications and the spinner turns only while a tool is running; I18N_KIT_WIDGET_STYLE=plain turns both off.

It mentions outstanding work when you sit down, follows a translate_missing run batch by batch instead of leaving a spinner with nothing behind it, reports what moved when the run ends — and then withdraws. A project with nothing missing gets no widget at all.

The reason is that a permanent line is an unread line. "Complete" says the same thing whether or not you have touched translations all day, and a missing count that has not moved in a week is wallpaper; worse, a percentage in a large project is pinned near 100 and moves in the third decimal, looking like a gauge while behaving like a constant. So the widget reports counts, briefly, and /i18n-coverage answers in full — percentages, per locale — when you actually ask. Like every other piece here it is silent outside kit projects.

Codex and Other Hosts

Codex CLI has no hook system, so the same rules travel as context instead of enforcement. The server block is on Set Up the MCP Server; next to it, put the rules where your host reads them — AGENTS.md for Codex:

AGENTS.md
## Translations

This project manages translations with the-i18n-kit (MCP server `the-i18n-kit`).

- Never edit locale files directly — one edited locale drifts from its
  siblings. Use `write_translations`, `translate_missing`, `translate_key`,
  `remove_translations`, `move_translation_key`.
- Start with `discover` to see locales, layers and the translation mode.
- Before finishing work that touched UI code, run `find_undefined_keys`;
  undefined keys render raw in production.
- Respect protected locales and preserve `{placeholders}` exactly.

Context is advice, and advice gets ignored. What the Stop hook enforces in-session, the pipeline enforces on every push: check exits non-zero on findings, wired through the GitHub Action or the GitLab CI template. A host without hooks loses the in-session correction, never the gate.

Long-Running Tools

translate_missing reports progress over MCP progress notifications — batch by batch, locale by locale — but only when the host asks for it, and hosts differ:

  • Claude Code requests progress and uses it to keep long calls alive; how much of it reaches the screen depends on the Claude Code version.
  • pi with pi-mcp-adapter's progress bridge renders each notification as a live partial result on the running tool call.
  • Hosts that request no progress get none — the server sends nothing rather than degrading the call.

The server side is the same in every case; a host upgrade is all it takes for progress to appear.

Copyright © 2026