Introduction

Built for Agents

The Claims and Their Mechanisms

ClaimMechanism
A large result never floods a context windowPass --output-file <path> (CLI) or outputFile (MCP) and the full JSON is written to disk; the caller receives { reportFile, summary }. Supported by missing, status, empty, check, scan, find-duplicates and remove-orphans, and their paired tools. Set reportOutput: true in your kit config to make it the default for every run, writing to .i18n-reports/<tool>.json
Report paths cannot escape the projectresolveOutputFile resolves relative paths against the project dir, not the process cwd, then rejects anything resolving outside it with a ToolError carrying code INVALID_REPORT_PATH
Third-party stdout cannot corrupt machine outputguardStdout() runs in the CLI entry point before any other module loads. It replaces process.stdout.write with a function that writes to stderr, and keeps the original bound reference. Command results go out through writeResult, which uses that captured reference. A Nuxt module that logs to stdout during config detection lands in stderr, and the JSON your agent parses stays one JSON document
Output is machine-readable without being askedoutputResult treats a non-TTY stdout as JSON mode. An agent spawning the CLI gets JSON without passing --json
A failed run still returns parseable JSONIn JSON mode, emitErrorResult writes { "error": { "code", "message" } } to the real stdout and sends the human-readable message to stderr. Zero bytes on stdout is a parse error for whatever is reading; an error object is not. Codes come from ToolError / FileIOError, from Node (ENOENT), or CONFIG_ERROR
Reads are targeted, not whole-file dumpsget --layer <l> --locale <c> --keys a.b,c.d returns those keys' values. search --query returns matches. missing returns what is absent. None of them require reading a locale file to find one string
Translate results account for every keyPer locale, missing = translated + wouldTranslate + failed + skipped. A run that quietly loses keys cannot balance, so an agent can verify completeness by arithmetic rather than by re-scanning. See translation modes
Failures are classified, not narratedfailed entries carry a reason from a closed set: provider-error, omitted-by-model, placeholder-mismatch, plural-mismatch, write-error, truncated. skipped entries carry no-provider, already-translated or protected-locale. An agent branches on the value instead of pattern-matching English
Provider failures are triaged before they cost you a runHTTP status is mapped at the provider boundary: 401/403 becomes auth and aborts the whole run with one error rather than failing key by key; 429 becomes rate-limit and is retried with backoff; a response cut off at the token limit is detected from the finish reason and reported as truncated, which tells the caller to lower batchSize
Uncertainty never becomes deletionremove-orphans defaults to dryRun: true, and remove_orphan_keys performs a dry run first. Keys reachable through a dynamic pattern, keys with ambiguous evidence (uncertainKeys) and keys used only from a non-consuming app (misplacedUsages) are reported in their own buckets and are never removed, including on a confirmed run
Exit codes are branchable0 succeeded with no gate tripped, 1 the run itself failed, 2 a requested gate tripped. The split lets a caller tell a bad API key from a project that has untranslated keys, without parsing the result
Which mode ran is always in the resultEvery translate result carries mode: "provider" | "agent" | "dry-run", and discover reports translationMode before any translation runs, so an agent can check the configuration without spending a call on it
Project context reaches the agent, not only the modeldiscover loads your kit config — context, glossary, translationPrompt, localeNotes, layerRules — into the session, so terminology decisions are made with the same information whoever wrote the glossary had

Agent Mode

With no provider configured — the default in an MCP host — the translate tools do not fail and do not silently do nothing. They return per-locale fallbackContexts: the source values plus the glossary, style notes and locale notes. Your agent translates them inline, using the model it is already running on, and persists the result through write_translations.

That is the difference between agent mode and provider mode, where the kit calls OpenAI, Anthropic or Google itself and writes the values directly. Both modes report themselves in the result — see translation modes for the full contract.

In the CLI, agent mode translates nothing. There is no model on the other end of a terminal, so keys are reported as skipped with reason no-provider. A CI job that forgets --provider therefore succeeds while translating zero keys — add --fail-on-missing if that should block.

Partial provider configuration — a provider with no model, or no key — logs a warning to stderr and falls back to agent mode. A misconfigured server degrades at startup rather than surprising a caller mid-request.

Writes an Agent Can Reason About

The write operations are deliberately narrow, so an agent picks by intent rather than by guessing at side effects:

ToolDoesDoes not
write_translationsWrites the exact values you passCall any model
translate_missingFills target locales that have no valueTouch existing values
translate_keyTranslates one source key into target locales, refreshing stale values when overwrite=trueTouch other keys

Values are validated before they are written: placeholder parity is checked per vue-i18n plural variant ({placeholders}, @:linked.refs, and :params for PHP), and the number of pipe-separated plural variants must match the source. A value that fails validation is rejected into failed rather than written, so a model dropping an interpolation cannot reach a locale file.

Limits

  • Context discipline is opt-in per call. Without --output-file / outputFile or reportOutput in the config, a large result is returned inline. Set reportOutput: true once rather than relying on remembering the flag.
  • The scanner is static and line-based. Keys built at runtime cannot be verified. They are classified as uncertain, which protects them from deletion but also means the orphan count is a floor, not a total.
  • Classified failure reasons are a closed set, and reality is not. A cause with no matching reason arrives as provider-error with the provider's message attached.
  • discover only knows what the config says. Layer rules and glossary terms nobody wrote down do not reach the agent.
Copyright © 2026