Wormhole is a command-line translator that rewrites Word (.docx) and PowerPoint (.pptx) files into another language while keeping the original layout intact. The tool walks every paragraph, table cell, header, footer, text box, and note, collects their text with deterministic identifiers, batches the content for an LLM, reinserts the translated text in place, and finally saves the result as a new document plus a friendly completion report.
The CLI is designed for teams that want a provider-agnostic workflow: switching to a different LLM requires only a new adapter, not a new command-line contract.
- Full support for
.docxand.pptxsources (body, tables, headers/footers, notes). - Deterministic IDs for every text unit to guarantee stable reinsertion.
- Layout-preserving reinsertion, even across runs with custom formatting.
- Batch planner that respects sentence boundaries with a default 2,000 character budget.
- Automatic retries, resumable error policy, and friendly messaging for interactive and non-interactive environments.
- Provider abstraction with an OpenAI implementation out of the box and support for
.envconfiguration viapython-dotenv.
- Python 3.13 (managed through uv).
- An OpenAI API key (
OPENAI_API_KEY) when using the default provider. - Optional
.envfile in the project root for environment configuration (OPENAI_API_KEY,WORMHOLE_PROVIDER_DEBUG, etc.).
-
Install uv
Follow the official uv installation guide: https://docs.astral.sh/uv/. -
Clone the repository
git clone https://github.com/your-org/wormhole.git cd wormhole -
Sync dependencies with uv
uv sync
uvreadspyproject.tomlanduv.lock, creating an isolated environment pinned to the recorded dependency versions. -
Configure credentials
Create a.envfile or export environment variables so the CLI can load your credentials:echo "OPENAI_API_KEY=sk-your-key" >> .env # Optional: override the default OpenAI model globally # echo "OPENAI_MODEL=gpt-4o-mini" >> .env # Optional additional flags: # echo "WORMHOLE_PROVIDER_DEBUG=1" >> .env
wormhole.clicallsload_dotenv()on startup, so entries in.envautomatically populate the environment.
Run the CLI through uv so dependencies resolve inside the managed environment:
# Show help
uv run python -m wormhole.cli --help
# Translate a document
uv run python -m wormhole.cli \
devloop.pptx \
--target-language en \
--source-language es \
--output devloop_en.pptx \
--verboseAlternatively, the project exposes a convenience entry point via main.py:
uv run main.py devloop.pptx --target-language enDuring execution Wormhole prints progress (and, optionally, provider debug output) and writes a summary that includes translated units, skipped elements, batch counts, and elapsed time. The original document remains untouched; the translated file is written to the path you specified or, by default, a sibling file suffixed with the sanitized target language.
Prefer a visual workflow? Launch the Tkinter GUI with ./wormhole.sh --gui on MacOS and Linux or ./wormhole.ps1 --gui on Windows; the window maps all core CLI options and still streams debug/verbose logs to the terminal.
For a complete technical overview including architecture diagrams, component descriptions, data flow, and design decisions, see TECHSPEC.md.
If you prefer a one-command launcher that manages the uv environment for you, use the included wrappers:
macOS/Linux (Bash/zsh):
./wormhole.sh --help
./wormhole.sh input.docx -t ES -s EN -o output_es.docx -vWindows or PowerShell Core:
./wormhole.ps1 --help
./wormhole.ps1 input.pptx -t EN -s ES -o output_en.pptx -vBoth launchers:
- Run
uv syncautomatically (setUV_SYNC=0to skip) - Forward all CLI arguments to the module (
wormhole.cli) - Accept extra uv options via
UV_ARGS(for example to pin Python):
UV_ARGS="--python 3.11" ./wormhole.sh --version| Option | Description | Notes |
|---|---|---|
input_file |
Path to the .docx or .pptx file to translate. |
Required positional argument. |
-t, --target-language |
Destination language (ISO-639 code or full name). | Required. |
-s, --source-language |
Optional source language hint. | Helps segmentation and provider prompts. |
-o, --output |
Output file path. | Defaults to appending the target language to the input stem; the input file is never overwritten. |
-p, --provider |
Translation provider identifier. | Defaults to openai. |
-m, --model |
Provider-specific model or engine name. | Overrides provider default (OpenAI reads OPENAI_MODEL if set, otherwise gpt-5.2). |
-b, --batch-guidance |
Approximate max characters per translation batch. | Integer, default 2000; sentences are kept intact where possible. |
-f, --force |
Allow overwriting an existing output file. | Without this flag, the CLI aborts if the output path exists. |
--non-interactive |
Disable prompts and automatic pauses. | Suitable for CI; still respects error thresholds. |
-v, --verbose |
Print detailed progress information. | Helpful for tracking segmentation and batches. |
--debug-provider |
Log full provider request/response payloads to stderr. | Equivalent env vars: WORMHOLE_PROVIDER_DEBUG=1 or WORMHOLE_DEBUG_PROVIDER=1. |
--gui |
Launch the Tkinter-based configuration window. | Ideal for interactive runs; CLI-only flags such as --verbose still print to the console. |
- The input document is opened read-only and never overwritten.
- If the output file exists and
--forceis not supplied, Wormhole exits with a friendly message. - Recoverable errors are retried automatically (up to three times per batch). After repeated failures, you can choose to continue, retry, or abort; in non-interactive mode the CLI continues until policy limits are exceeded.
- Irrecoverable errors (missing files, unsupported types, configuration issues) produce human-readable guidance and exit with a non-zero code.
The default OpenAI provider reads OPENAI_API_KEY from the environment. The adapter can be extended to support alternate providers while keeping the existing CLI contract intact. Provider debugging can be enabled via the --debug-provider flag or either WORMHOLE_PROVIDER_DEBUG=1 or WORMHOLE_DEBUG_PROVIDER=1 in the environment.
Wormhole ships with a single OpenAI adapter that understands two transport modes:
- OpenAI / Azure OpenAI (Responses API) — the default path, using OpenAI's Responses endpoint (and the Azure equivalent) for JSON-native output.
- Legacy OpenAI (Completions API) — an opt-in fallback for deployments that have not enabled the Responses API yet.
Select the correct backend through environment variables:
LLM_PROVIDER=openai(default) usesOPENAI_API_KEY.- Optionally set
OPENAI_MODELto override the default model without passing--model.
- Optionally set
LLM_PROVIDER=azure_openaiswitches the same adapter to Azure OpenAI; provide:AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_VERSIONAZURE_OPENAI_DEPLOYMENT_NAMEAZURE_OPENAI_EMBEDDING_MODEL
Usage examples:
# Responses API with OpenAI (default provider)
uv run python -m wormhole.cli input.docx -t es
# Responses API with Azure OpenAI
LLM_PROVIDER=azure_openai \
AZURE_OPENAI_API_KEY=... \
AZURE_OPENAI_ENDPOINT=https://your-endpoint.openai.azure.com \
AZURE_OPENAI_API_VERSION=2024-12-01-preview \
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o \
uv run python -m wormhole.cli input.docx -t es
# Chat Completions via the legacy adapter
uv run python -m wormhole.cli input.docx -t es --provider legacy-openaiChoose the legacy adapter only when your account cannot access the Responses API; it emits the same JSON contract but leverages the Chat Completions endpoint behind the scenes.
This project uses Pengu — a tool that gives you a persistent Linux environment in a container, instantly available from any operating system.
Get started:
# Install Pengu (Linux/macOS)
curl -fsSL https://raw.githubusercontent.com/soyrochus/pengu/main/pengu-install.sh | bash -s -- -y
# Start your Linux environment
./pengu up && ./pengu shellWindows:
iwr -useb https://raw.githubusercontent.com/soyrochus/pengu/main/pengu-install.ps1 | iex
.\pengu.ps1 up; .\pengu.ps1 shellYour project files are available at /workspace with all dependencies pre-configured. No local setup required.
Everyone is invited and welcome to contribute: open issues, propose pull requests, share ideas, or help improve documentation.
Participation is open to all, regardless of background or viewpoint.
This project follows the FOSS Pluralism Manifesto,
which affirms respect for people, freedom to critique ideas, and space for diverse perspectives.
Copyright (c) 2025, Iwan van der Kleijn
This project is licensed under the MIT License. See the LICENSE file for details.

