---
title: "verbatra init"
description: "Lege eine verbatra-Konfiguration und ein .env-Beispiel für dieses Projekt an, erkannt aus deinen Locale-Dateien, interaktiv oder vollständig unbeaufsichtigt."
type: "reference"
---
# verbatra init

Lege eine verbatra-Konfiguration und ein .env-Beispiel für dieses Projekt an, erkannt aus deinen Locale-Dateien, interaktiv oder vollständig unbeaufsichtigt.

Setze ein Projekt auf: `init` schreibt eine `verbatra.config.ts`, eine `.env.example`, die die API-Key-Variable deines Providers nennt (nie einen Key-Wert), und die `.gitignore`-Einträge für `.env`, `.env.local`, `.verbatra-local/` und `verbatra.cache.json`. Es liest zuerst die Locale-Dateien im Projekt, meist musst du ihm also nur den Provider sagen.

## Synopsis [#synopsis]

```bash
verbatra init [flags]
```

## Beispiele [#beispiele]

```bash
# prompt for anything not passed or detected
verbatra init --provider gemini

# fully unattended, one JSON document on stdout
verbatra init --provider gemini --yes --json

# choose the format and pattern yourself
verbatra init --provider deepl --format yaml --path "config/locales/{locale}.yml" --yes

# a local server that needs no key
verbatra init --provider openai-compatible --base-url http://localhost:11434/v1 --model llama3.1 --yes

# a self-hosted LibreTranslate server, no language model
verbatra init --provider libretranslate --base-url http://localhost:5000 --yes

# human-only: no provider, no API key
verbatra init --provider none --yes

# also set the project up for coding agents
verbatra init --provider gemini --yes --agent

# wire Cursor and VS Code, and only show what would change
verbatra init --agent --client cursor,vscode --dry-run
```

## Flags [#flags]

| Flag | Argument | Standard | Wirkung |
| --- | --- | --- | --- |
| `--provider` | `<id>` | keiner (erforderlich, sofern nicht abgefragt) | Provider, der aufgesetzt wird: `anthropic`, `openai`, `gemini`, `deepl`, `google-translate`, `opencode`, `openai-compatible`, `libretranslate` oder `none` |
| `--format` | `<id>` | erkannt, sonst `i18next-json` | das Format der Locale-Dateien, eine der IDs unter [Formate](https://verbatra.kreitz-webdev.de/de/docs/formats.md) |
| `--source` | `<locale>` | erkannt, sonst `en` | die Quell-Locale, in der deine Strings geschrieben sind |
| `--targets` | `<locales>` | erkannt, sonst `de` | kommagetrennte Ziel-Locales, in die übersetzt wird |
| `--path` | `<pattern>` | erkannt, sonst das übliche Layout des Formats ([Erkennung](#erkennung)) | Muster der Locale-Dateien; muss das Token `{locale}` enthalten |
| `--model` | `<name>` | der Standard des Scaffolds | das Modell; erforderlich für `openai-compatible`, optional für `anthropic`, `openai`, `gemini` und `opencode` |
| `--base-url` | `<url>` | keiner | die Server-URL; nur für `openai-compatible` und `libretranslate` und dort erforderlich |
| `--api-key-env-var` | `<name>` | `OPENAI_COMPATIBLE_API_KEY` | die Variable, aus der `openai-compatible` seinen Key liest |
| `--yes` | keins | aus | nie nachfragen; für alles, was weder übergeben noch erkannt wurde, den Standardwert nehmen |
| `--force` | keins | aus | eine bestehende `verbatra.config.ts` mit abweichendem Inhalt überschreiben |
| `--agent` | keins | aus | zusätzlich den Abschnitt für Coding-Agenten in `AGENTS.md` oder `CLAUDE.md` und den verbatra-MCP-Server in die Projektkonfiguration jedes erkannten Clients schreiben ([Coding-Agenten einrichten](#coding-agenten-einrichten)) |
| `--client` | `<ids>` | erkannt | kommagetrennte Clients, die `--agent` statt der erkannten einrichtet: `claude`, `cursor`, `vscode`, `codex`, `gemini` oder `all`; braucht `--agent` |
| `--dry-run` | keins | aus | jede Datei melden, die `init` schreiben oder ändern würde, und nichts schreiben ([Probelauf](#probelauf)) |

Nimmt außerdem die [globalen Flags](https://verbatra.kreitz-webdev.de/de/docs/cli.md#globale-flags) `--cwd` und `--json`, aber nicht `--config`. Hier ist `--cwd` das Verzeichnis, das durchsucht und beschrieben wird, und es muss schon existieren. `--json` fragt nie nach.

## Verhalten [#verhalten]

### Rückfragen [#rückfragen]

<AvailableFrom version="0.12.0" />

Ein Flag gewinnt immer. Was du weglässt, wird aus dem Projekt erkannt, dann abgefragt, wenn stdin ein Terminal ist und weder `--yes` noch `--json` angegeben ist, und sonst nur unter `--yes` aus seinem Standardwert genommen. Enter übernimmt den vorgeschlagenen Wert. Ein Flag mit leerem Wert, etwa `--targets ''`, ist ein Verwendungsfehler (`INVALID_OPTION`) und nie eine Bitte um den Standardwert. Endet stdin bei einer Abfrage (Ctrl-D), bricht `init` mit `2` und `MISSING_OPTIONS` ab.

Jede Antwort wird sofort geprüft. Eine ungültige wird auf stderr erklärt und bis zu dreimal neu abgefragt, deine bisherigen Antworten bleiben erhalten; nach der dritten ungültigen Antwort bricht `init` mit dem Fehlercode dieser Antwort ab (etwa `INVALID_LOCALE`), nennt das Flag, das du stattdessen übergeben kannst, und schreibt nichts.

### Erkennung [#erkennung]

`init` durchsucht das Verzeichnis nach Dateien, die ein Format-Adapter beansprucht, überspringt versteckte Verzeichnisse, `node_modules` und Build-Ausgabe und findet den Teil jedes Pfads, der eine Locale ausschreibt, etwa `de.json`, `messages_pt_BR.properties`, `de.lproj/` oder Androids `values-de/`. Das Dateimuster, das die meisten Locales abdeckt, gewinnt, und daraus ergeben sich:

- `format`: das eine Format, dessen Adapter jede gefundene Datei liest. Jeder JSON-Adapter liest `.json`, deshalb entscheidet bei JSON-Dateien eine einzelne passende Dependency in `package.json` (`i18next`, `vue-i18n`, `next-intl` oder `@ngx-translate/core`).
- `files.pattern` und `files.localeStyle`: `posix`, wenn die Dateien `pt_BR` schreiben, `android` für `values-*`-Verzeichnisse, sonst `literal`.
- `sourceLocale`: die Quellsprache eines `.xcstrings`-Katalogs, sonst `en` oder die einzige gefundene `en-*`-Locale, sonst die einzige gefundene Locale.
- `targetLocales`: jede andere gefundene Locale.

Eine Datei neben den Locale-Dateien, die Strings unter keinem Locale-Namen enthält, etwa `messages.properties`, `Strings.resx` oder eine gettext-Datei `app.pot`, wird als `unqualifiedSourceFile` gemeldet. verbatra kann die Quelle nicht aus so einer Datei lesen, deshalb rät `init` die Quell-Locale nicht: Übergib `--source`, auch mit `--yes`, und die nächsten Schritte nennen die Datei, in die du die Basisdatei umbenennen oder kopieren sollst.

Gibt es gar keine Locale-Datei, entscheiden allein die Dependencies über das Format, und das Muster folgt dem üblichen Layout des Formats, wie es für jedes Format unter [Wähle deinen Stack](https://verbatra.kreitz-webdev.de/de/docs/pick-your-stack.md) steht.

Ein `apple-xcstrings`-Katalog ist eine einzige Datei für alle Locales, und verbatra legt ihn nie an: Erstelle ihn zuerst in Xcode. `--format`, `--path` und `--source` grenzen die Erkennung ein, statt von ihr überschrieben zu werden, `--format yaml` sieht sich also nur YAML-Dateien an.

`init` rät nie zwischen Gleichwertigen. Lesen mehrere Formate die Dateien (reines JSON ohne i18n-Dependency), endet es mit `2` und `FORMAT_AMBIGUOUS`, und liegen mehrere Dateimuster gleichauf (eine Datei pro Namespace), mit `2` und `LAYOUT_AMBIGUOUS`. Beide listen die Kandidaten auf; übergib `--format` oder `--path`, um einen zu wählen. Am Terminal fragt es stattdessen nach.

### Unbeaufsichtigte Läufe [#unbeaufsichtigte-läufe]

Ohne Terminal oder mit `--json` fragt `init` nie nach. Ein Wert, der weder übergeben noch erkannt noch durch `--yes` gefüllt wird, ist ein Fehler: `init` endet mit `2` und `MISSING_OPTIONS` und nennt alle fehlenden Flags auf einmal. Eine Mehrdeutigkeit oder ein ungültiges Flag listet zusätzlich die noch fehlenden Flags auf, sodass ein einziger Lauf einem Agenten alles sagt, was er übergeben muss. `--provider` hat keinen Standardwert, ebenso wenig `--base-url` und `--model` für `openai-compatible` oder `--base-url` für `libretranslate`. Diesen Befehl führt ein Agent aus:

```bash
npx @verbatra/cli init --provider gemini --yes --json
```

### JSON-Ausgabe [#json-ausgabe]

Schema: [`init-envelope.json`](https://verbatra.kreitz-webdev.de/schema/v1/init-envelope.json) validiert den ganzen Envelope; [Schemas](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#schemas) listet die übrigen auf.

Mit `--json` steht auf stdout genau ein [Envelope](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#json-ausgabe). Sein `result`:

```ts
interface InitResult {
  configPath: string;                  // absolute path of verbatra.config.ts, or of the config --agent kept
  files: { path: string; action: "created" | "overwritten" | "updated" | "unchanged" }[];
  dryRun: boolean;                     // true under --dry-run: files holds the planned actions
  config: {                            // the config that was validated and written
    sourceLocale: string;
    targetLocales: string[];
    format: string;
    files: { pattern: string; localeStyle?: "posix" | "android" };
    provider: { id: string; options?: Record<string, unknown> };
    sensitiveData?: { mode: "warn" };
  } | null;
  sources: {                           // where each value came from
    provider: "flag" | "prompt";
    format: "flag" | "prompt" | "files" | "dependencies" | "default";
    pattern: "flag" | "prompt" | "detected" | "default";
    sourceLocale: "flag" | "prompt" | "detected" | "default";
    targetLocales: "flag" | "prompt" | "detected" | "default";
  } | null;
  apiKeyEnvVar: string | null;         // the variable to set; null for provider none
  detection: {
    format: { id: string; from: "input" | "files" | "dependencies" } | null;
    layout: {
      pattern: string;
      localeStyle: "literal" | "posix" | "android";
      locales: string[];
      sourceLocale: string | null;
      unqualifiedSourceFile: string | null;
      files: string[];
    } | null;
    ambiguities: { subject: "format" | "layout"; candidates: string[] }[];
    confidence: "high" | "medium" | "low" | "none";
    reasons: string[];                 // one sentence per decision or doubt
  } | null;
  agent: {                             // null without --agent
    instructionsFile: "AGENTS.md" | "CLAUDE.md";
    mcpServer: "added" | "present" | "differs" | "skipped" | null; // Claude Code; null when not wired
    configKept: boolean;               // true when --agent kept an existing config
    clients: {
      id: "claude" | "cursor" | "vscode" | "codex" | "gemini";
      file: string;                    // the client's config file, such as .mcp.json
      server: "added" | "present" | "differs" | "skipped";
      reason: "plugin" | "symlink" | null; // why the client was skipped
      selectedBy: "flag" | "markers" | "default";
      markers: string[];               // the client's marker files found in the project
    }[];
  } | null;
  nextSteps: { description: string; command: string | null }[];
}
```

`confidence` ist `high`, wenn allein die Dateien alles entschieden haben, `medium`, wenn eine Konvention oder eine Dependency eine Lücke gefüllt hat (etwa `en` als Quelle) oder eine Lücke offen blieb, `low`, wenn keine Locale-Datei das Format gestützt hat, und `none`, wenn nichts erkannt wurde. Ein `default` in `sources` ist der Wert, den du noch einmal prüfen solltest. `nextSteps` endet mit den genauen nächsten Befehlen.

Ein Fehler-Envelope für `FORMAT_AMBIGUOUS`, `LAYOUT_AMBIGUOUS`, `INVALID_PROVIDER` oder `INVALID_FORMAT` trägt zusätzlich `candidates`, die Werte zur Auswahl. Jeder Verwendungsfehler, der Flags unbeantwortet lässt, trägt `missing` mit ihren Namen, etwa `"--source <locale>"`.

### Provider [#provider]

<AvailableFrom version="0.12.0" />

- `--provider none` legt eine [rein menschliche](https://verbatra.kreitz-webdev.de/de/docs/human-only-workflow.md) Konfiguration ohne `options` an und schreibt keine `.env.example`, weil nie ein API-Key gelesen wird.
- `--provider openai-compatible` setzt einen lokalen oder selbst gehosteten Server aus `--base-url` und `--model` auf, mit `maxOutputTokens: 4096`. Sein Key ist optional: Ein Server, der keinen braucht, lässt `OPENAI_COMPATIBLE_API_KEY` ungesetzt, und `--api-key-env-var` nennt eine andere Variable, in Großbuchstaben wie `LLM_API_KEY`. Ein abgelehnter Wert wird nie wiederholt, falls es der Key selbst war.
- `--provider libretranslate` setzt einen selbst gehosteten [LibreTranslate](https://verbatra.kreitz-webdev.de/de/docs/providers.md#libretranslate)-Server allein aus `--base-url` auf, etwa `http://localhost:5000`, und lehnt `--model` und `--api-key-env-var` ab. `.env.example` nennt `LIBRETRANSLATE_API_KEY` für einen Server, der mit `--api-keys` gestartet wurde.

`init` schreibt den Namen einer Variable in die Konfiguration und in `.env.example`, nie einen Wert, und lehnt eine Base-URL mit Zugangsdaten, Query-String oder Fragment ab (`https://user:key@host`, `https://host/v1?api-key=...`), über die ein Key in der eingecheckten Konfiguration landen könnte.

### Bestehende Dateien [#bestehende-dateien]

Ein erneutes `init` mit denselben Antworten ändert nichts und ist erfolgreich. Eine `verbatra.config.ts` mit anderem Inhalt wird mit `CONFIG_EXISTS` abgelehnt, außer du übergibst `--force`, und diese Ablehnung kommt vor jeder Frage und jedem anderen Fehler. Eine andere verbatra-Konfiguration im Verzeichnis (eine `.verbatrarc.json` oder eine `verbatra`-Property in `package.json`) wird auch unter `--force` abgelehnt, weil sie zuerst gelesen würde. Wenn `init` ablehnt, wird nichts geschrieben. Deckt eine Konfiguration in einem übergeordneten Verzeichnis dieses mit ab, warnt `init` auf stderr (auch im Dry Run): Die neue `verbatra.config.ts` ersetzt sie hier.

Ein Verzeichnis, in das `init` nicht schreiben kann, wird mit `INIT_UNWRITABLE` abgelehnt, samt der Datei und jeder schon geschriebenen Datei. Eine `verbatra.config.ts`, `.env.example` oder `.gitignore`, die ein symbolischer Link aus dem Projekt hinaus oder ins Leere ist, wird mit `INIT_UNWRITABLE` abgelehnt, bevor irgendetwas geschrieben wird. Eine bestehende `.env.example` bleibt; nennt sie die Key-Variable noch nicht, wird genau diese Zeile angehängt, und unter `--force` wird eine Kopfzeile, die `init` selbst geschrieben hat, für den neuen Provider neu geschrieben. `.gitignore` bekommt nur die Einträge, die ihr fehlen.

### Probelauf [#probelauf]

<AvailableFrom version="0.12.0" />

`--dry-run` durchläuft jede Prüfung und Ablehnung eines echten Laufs außer einem fehlgeschlagenen Schreibvorgang, etwa in einem schreibgeschützten Verzeichnis, gibt für jede Datei `would create`, `would update`, `would overwrite` oder `unchanged` aus und schreibt nichts. Das JSON-Ergebnis listet die geplanten Aktionen und setzt `dryRun` auf `true`.

### Coding-Agenten einrichten [#coding-agenten-einrichten]

<AvailableFrom version="0.12.0" />

`--agent` bereitet das Projekt zusätzlich für Coding-Agenten vor. Es schreibt keinen Key-Wert, schreibt nie durch einen Link aus dem Projekt hinaus und legt an:

- **Die Anweisungsdatei.** Ein verbatra-Abschnitt zwischen den Markierungen `<!-- verbatra:start -->` und `<!-- verbatra:end -->`, Wort für Wort das Snippet aus [Deinem Agenten von verbatra erzählen](https://verbatra.kreitz-webdev.de/de/docs/agent-recipes.md#deinem-agenten-von-verbatra-erzählen). Es landet in `AGENTS.md` oder in `CLAUDE.md`, wenn das die einzige Anweisungsdatei ist; gibt es beide, gewinnt `AGENTS.md`. Enthält eine Datei den Abschnitt schon, wird der Text zwischen den Markierungen durch den aktuellen ersetzt und als `updated` gemeldet, oder als `unchanged`, wenn er schon passt.
- **Die MCP-Konfiguration jedes Clients.** Der `verbatra`-Servereintrag aus [MCP-Client verbinden](https://verbatra.kreitz-webdev.de/de/docs/connect-an-mcp-client.md), `npx -y @verbatra/mcp` ohne `--allow-spend` und ohne `VERBATRA_MCP_ALLOW_SPEND`, sodass die Tools, die Geld kosten, verborgen bleiben. `@verbatra/cli` exportiert diese Einträge als `AGENT_CLIENT_CONFIGS`.

| Client | `--client` | Datei | Erkannt an |
| --- | --- | --- | --- |
| Claude Code | `claude` | `.mcp.json` | `CLAUDE.md`, `.claude/`, `.mcp.json` |
| Cursor | `cursor` | `.cursor/mcp.json` | `.cursor/`, `.cursorrules` |
| VS Code | `vscode` | `.vscode/mcp.json`, unter `servers` | `.vscode/mcp.json` |
| Codex | `codex` | `.codex/config.toml`, als `[mcp_servers.verbatra]` | `.codex/` |
| Gemini CLI | `gemini` | `.gemini/settings.json` | `.gemini/`, `GEMINI.md` |

`init` richtet jeden erkannten Client ein, und nur Claude Code, wenn es keine Markierungsdatei findet. `AGENTS.md` wählt die Anweisungsdatei, keinen Client. Ein `.vscode`-Ordner ohne `mcp.json` wird nicht eingerichtet: Ein nächster Schritt nennt den Befehl dafür. Gemini CLI liest `GEMINI.md`: Laden seine Einstellungen oder `GEMINI.md` die Anweisungsdatei nicht, sagt ein nächster Schritt, wie. Ein erkannter Client, dessen Konfigurationspfad über einen symbolischen Link führt, wird mit dem Grund `symlink` und einem nächsten Schritt übersprungen. `--client` ersetzt die Erkennung; eine unbekannte ID, eine leere Liste oder `--client` ohne `--agent` endet mit `2` und `INVALID_OPTION` samt den Kandidaten.

Außerhalb der Markierungen wird nichts angefasst, und andere Server und Schlüssel behalten ihre Bytes, Einrückung und Zeilenenden, wenn die Datei einen Eintrag pro Zeile hat; sonst wird sie mit demselben Inhalt neu geschrieben. Die Codex-Tabelle wird angehängt. Ein vorhandener `verbatra`-Server wird nie angefasst: Die Datei wird als `unchanged` gemeldet, und `server` des Clients ist `present`, wenn der Eintrag dem Scaffold entspricht, oder `differs`, wenn nicht, was zusätzlich einen Hinweis in `nextSteps` ergibt.

Aktiviert `.claude/settings.json` oder `.claude/settings.local.json` das verbatra-Plugin für Claude Code, überspringt `init` die `.mcp.json`: Claude Code wird als `skipped` mit dem Grund `plugin` und einem nächsten Schritt gemeldet, und ein vorhandener Eintrag wird nie gelöscht. Eine Einstellungsdatei hinter einem symbolischen Link wird ignoriert.

In einem Projekt, das schon eine Konfiguration hat, schreibt `init --agent` nur die Agenten-Dateien, behält die Konfiguration, gibt `kept verbatra.config.ts` aus, fragt nie nach und erkennt nichts. Das JSON-Ergebnis führt die Konfiguration als `unchanged`, setzt `agent.configKept` auf `true` und enthält `null` für `config`, `sources`, `apiKeyEnvVar` und `detection`. Ein Konfigurations-Flag oder `--force` nimmt die Konfiguration wieder in den Lauf auf, wie ohne `--agent`.

`init` lehnt mit `AGENT_FILE_INVALID` ab, bevor irgendetwas geschrieben wird, wenn eine Client-Datei kein reines JSON ist (Kommentare oder nachgestellte Kommas schreibt es nie um), kein Objekt ist, einen Schlüssel wiederholt oder einen Server-Wert hat, der kein Objekt ist; wenn `.codex/config.toml` `mcp_servers` oder den verbatra-Server inline, mit gepunkteten Schlüsseln oder als Array von Tabellen setzt, diese Tabelle oder einen Schlüssel darin wiederholt oder einen nicht abgeschlossenen String, ein offenes Array oder einen offenen Header hat; wenn ein Client, den `--client` nennt, einen symbolischen Link auf seinem Konfigurationspfad hat oder eine Anweisungsdatei aus dem Projekt hinaus verlinkt; oder wenn die Anweisungsdatei eine ungepaarte, falsch geordnete oder doppelte Markierung hat. Die Meldung zitiert die Datei nie.

## Exit-Codes [#exit-codes]

| Code | Bedeutung |
| --- | --- |
| `0` | Dateien geschrieben oder schon auf dem aktuellen Stand |
| `2` | ein Verwendungsfehler: `MISSING_OPTIONS`, `INVALID_PROVIDER`, `INVALID_FORMAT`, `INVALID_OPTION`, `INVALID_LOCALE`, `INVALID_LOCALES`, `FORMAT_AMBIGUOUS`, `LAYOUT_AMBIGUOUS`, `CONFIG_EXISTS`, `INIT_UNWRITABLE`, `AGENT_FILE_INVALID` oder `CONFIG_INVALID`, wenn die Antworten keine gültige Konfiguration ergeben würden |

Wie jeder Befehl diese Codes nutzt, steht im [Exit-Code-Vertrag](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#exit-codes).

## Siehe auch [#siehe-auch]

- [verbatra mit einem KI-Agenten einrichten](https://verbatra.kreitz-webdev.de/de/docs/start-with-ai.md) ist der Agenten-Prompt, der auf diesem Befehl aufbaut.
- [Schnellstart](https://verbatra.kreitz-webdev.de/de/docs/quickstart.md) führt von init bis zum ersten Lauf.
- [Konfigurationsdatei](https://verbatra.kreitz-webdev.de/de/docs/config-file.md) dokumentiert jeden Key, den das Scaffold setzt.
- [Provider](https://verbatra.kreitz-webdev.de/de/docs/providers.md) behandelt die Provider-Optionen und API-Key-Variablen.
