# 2494 Agents Full Reference V19313 2026 02 23 B581da1a

> Supervertaler - AI Agent Documentation

- Skill: `tools-only/2494-agents-full-reference-v19313-2026-02-23-b581da1a` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/2494-agents-full-reference-v19313-2026-02-23-b581da1a`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/2494-agents-full-reference-v19313-2026-02-23-b581da1a/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/tools-only/2494-agents-full-reference-v19313-2026-02-23-b581da1a

---

# Supervertaler - AI Agent Documentation

> **This is the single source of truth for AI coding assistants working on this project.**
> **Last Updated:** February 23, 2026 | **Version:** v1.9.313

---

## ⚡ QUICK START FOR AI AGENTS

**IMPORTANT: If you're continuing from a previous session or ran out of context:**

1. **Skip to the end of this file** - The most recent development context is in the **"🔄 Recent Development History"** section (search for the latest date)
2. **Current version: v1.9.313** - SDLPPX multi-file views, locked segment toggle, memoQ submenu
3. **Read only what you need** - The Project Overview and Architecture sections are reference material; the dated history entries contain the actual working context

**Quick Navigation:**
- **Latest context:** See CHANGELOG.md for v1.9.311-313 (Trados SDLXLIFF/SDLPPX improvements)
- **Module list:** Search for `## 🔌 Complete Module List`
- **Architecture:** Search for `## 🏗️ Architecture Patterns`
- **Common pitfalls:** Search for `## ⚠️ Common Pitfalls`

---

## 🎯 Project Overview

**Supervertaler** is a professional desktop translation application built with Python and PyQt6. It serves as a companion tool for translators, integrating AI-powered translation with traditional CAT (Computer-Assisted Translation) tool workflows.

| Property | Value |
|----------|-------|
| **Name** | Supervertaler |
| **Version** | v1.9.313 (February 2026) |
| **Framework** | PyQt6 (Qt for Python) |
| **Language** | Python 3.10+ |
| **Platform** | Windows (primary), Linux compatible |
| **Repository** | https://github.com/michaelbeijer/Supervertaler |
| **Website** | https://supervertaler.com |
| **Main File** | `Supervertaler.py` (~56,000+ lines) |
| **Modules** | 85+ specialized modules in `modules/` directory |

### Key Capabilities

- **Multi-LLM AI Translation**: OpenAI GPT-4, Anthropic Claude, Google Gemini, Local Ollama, Custom OpenAI-Compatible API (Volcengine/Doubao, Tongyi/Qwen, DeepSeek, etc.)
- **CAT Tool Integration**: Trados SDLPPX/SDLRPX, memoQ XLIFF/DOCX/RTF, Phrase/Memsource DOCX, CafeTran DOCX, Déjà Vu X3 RTF
- **Translation Memory**: Fuzzy matching TM with TMX import/export + Supermemory (ChromaDB vector search)
- **Terminology Management**: SQLite-based termbases with priority highlighting and automatic extraction
- **Document Handling**: DOCX, bilingual DOCX, PDF (via OCR), simple TXT, **Markdown (MD)**, **Multi-file folder import**
- **Quality Assurance**: Spellcheck, tag validation, consistency checking
- **Superlookup**: Unified concordance hub with TM, Termbase, Supermemory, MT, and Web Resources
- **Batteries Included**: Default install includes all major features and dependencies, except heavy optional components (Supermemory + offline Local Whisper)

---

## 📦 Installation (Simplified)

Supervertaler uses a batteries-included *core* install: `pip install supervertaler` pulls in everything needed for the major features, while keeping heavy optional components out of the default install.

**Note:** Offline dictation via Local Whisper is optional because it pulls in very large dependencies (PyTorch). The default/recommended voice path uses the OpenAI Whisper API.

**Legacy note:** older “extras” (e.g. `supervertaler[all]`) are still accepted for backward compatibility, but they no longer change what gets installed.

### Installation Options

| Command | Notes |
|---------|-------|
| `pip install supervertaler` | Recommended core install (excludes heavy optional Local Whisper) |
| `pip install supervertaler[local-whisper]` | Adds offline Local Whisper (heavy; pulls PyTorch) |
| `pip install supervertaler[all]` | Legacy alias (no-op; kept for compatibility) |

### Feature Modules

| Module | Included by default | Size | Description |
|--------|----------------------|------|-------------|
| **Supervoice** | ✅ | ~150 MB | Voice dictation & commands (OpenAI Whisper API recommended) |
| **Web Browser** | ✅ | ~100 MB | Built-in browser for Superlookup |
| **PDF Rescue** | ✅ | ~30 MB | PDF text extraction/OCR |
| **MT Providers** | ✅ | ~30 MB | DeepL, Amazon Translate |
| **Hunspell** | ✅ | ~20 MB | Advanced spellcheck |
| **AutoFingers** | ✅ (Windows) | ~10 MB | Windows automation |

### Settings → Features Tab

Users can enable/disable features in **Settings → 📦 Features**.

### Feature Manager Module

The `modules/feature_manager.py` provides:
- `FeatureManager` class for checking feature availability
- `FEATURE_MODULES` dict defining all optional features
- `lazy_import_*()` functions for conditional imports
- `check_feature(id)` quick availability check

---

## 🪟 Windows EXE Releases (CORE + FULL)

Supervertaler Windows releases are published as **two separate ZIP assets** on the same GitHub Release:

1) **CORE** (recommended for most users)
- Smaller download
- Does **not** bundle the heavy ML stack (Supermemory + offline Local Whisper)

2) **FULL** ("batteries included")
- Larger download
- Bundles **Supermemory** + **offline Local Whisper** (PyTorch / sentence-transformers / ChromaDB)

### Key Rule (PyInstaller one-folder builds)

The EXE must be run from the extracted distribution folder. Do **not** separate `Supervertaler.exe` from `_internal/`.

If users see an error like missing `python312.dll`, they are almost always:
- running the wrong EXE (from an intermediate build folder), or
- moving the EXE away from `_internal/`.

### How to Build (recommended)

Use the automated build script:

```powershell
# Build BOTH core + full and create both ZIP assets
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1

# Build only core
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -CoreOnly

# Build only full
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -FullOnly

# Clean build venvs + rebuild (keeps dist/ so multi-flavor builds can coexist)
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -Clean
```

What it does:
- Uses two isolated build environments: `.venv-build-core` and `.venv-build-full`
- Runs PyInstaller with the corresponding spec:
  - `Supervertaler.core.spec` → `dist\Supervertaler-core\...`
  - `Supervertaler.full.spec` → `dist\Supervertaler-full\...`
- Zips each output using `create_release_zip.py` and writes a `README_FIRST.txt` into each dist folder.

### Output Files

After a successful run, you should have:
- `dist\Supervertaler-v<version>-Windows-CORE.zip`
- `dist\Supervertaler-v<version>-Windows-FULL.zip`

### GitHub Release Posting

Attach **both** ZIP files to the same GitHub Release tag.

### VS Code Tasks

There are build tasks wired up in `.vscode/tasks.json`:
- "Build Windows EXE (core)"
- "Build Windows EXE (full)"
- "Build Windows EXE (core + full)"

---

## 📁 Project Structure

```
Supervertaler/
├── Supervertaler.py          # Main application (~56,000+ lines)
├── modules/                   # 85+ specialized modules
│   ├── feature_manager.py    # Modular feature management (NEW)
│   ├── llm_clients.py        # OpenAI, Anthropic, Google Gemini, Ollama
│   ├── translation_memory.py # TM matching and storage
│   ├── termbase_manager.py   # Terminology management
│   ├── docx_handler.py       # DOCX import/export
│   ├── sdlppx_handler.py     # Trados Studio packages
│   ├── phrase_docx_handler.py# Phrase/Memsource bilingual
│   ├── cafetran_docx_handler.py # CafeTran bilingual
│   ├── supermemory.py        # Vector-indexed semantic TM (ChromaDB)
│   ├── spellcheck_manager.py # Spellcheck with pyspellchecker/Hunspell
│   ├── prompt_library.py     # AI prompt management
│   └── ...                   # See module list below
├── user_data/                 # User content (gitignored)
│   ├── prompts/              # .svprompt files
│   ├── termbases/            # .db termbase files
│   ├── translation_memories/ # .db TM files
│   ├── dictionaries/         # Custom spellcheck words
│   └── supermemory/          # ChromaDB vector database
├── assets/                    # Icons, images
├── docs/                      # Documentation site
├── beijerterm/                # 🔗 GIT SUBMODULE - Beijerterm glossary website
├── tests/                     # Test files
└── legacy_versions/           # Historical Tkinter version
```

---

## 🔗 Beijerterm Website Submodule (IMPORTANT FOR AI AGENTS)

The `beijerterm/` folder is a **Git submodule** - a separate repository embedded inside Supervertaler.

### What is a Submodule?

- It's a **pointer** to a specific commit in another repository
- Regular `git clone` does NOT download submodule contents (saves ~15 MB)
- The submodule has its own `.git` and tracks `michaelbeijer/beijerterm` separately

### Two Separate Projects

| Project | Location | Purpose |
|---------|----------|---------|
| **Supervertaler** | Root folder | PyQt6 translation app |
| **Beijerterm** | `beijerterm/` subfolder | Static glossary website (beijerterm.com) |

**Note**: The "Superlookup" name refers to the in-app lookup panel inside Supervertaler - don't confuse it with the Beijerterm website!

### Working with the Submodule

**To make changes to Beijerterm website:**
```bash
cd beijerterm/
# Edit files...
git add .
git commit -m "your message"
git push origin main          # Pushes to michaelbeijer/beijerterm
```

**Then update the parent reference:**
```bash
cd ..                          # Back to Supervertaler root
git add beijerterm             # Stage the new submodule commit pointer
git commit -m "chore: Update beijerterm submodule"
git push origin main           # Pushes to michaelbeijer/Supervertaler
```

### ⚠️ Common Pitfalls

1. **Commits in submodule aren't automatically tracked** - After committing inside `beijerterm/`, you must also commit in the parent repo to update the pointer.

2. **Changelogs are separate** - Beijerterm website changes go in `beijerterm/CHANGELOG.md`, Supervertaler changes go in `CHANGELOG.md` at root.

3. **Features in the wrong repo** - The "Superlookup" panel inside Supervertaler.py is part of **Supervertaler**, not the Beijerterm website. Don't confuse them!

4. **Building the website** - Run `python scripts/build_site.py` from inside `beijerterm/`, not from root.

---

## 🔧 Key Technical Details

### Main Application (`Supervertaler.py`)

The main file is a large monolithic PyQt6 application. Key sections:

| Line Range | Purpose |
|------------|---------|
| 1-700 | Imports, constants, Project dataclass |
| 700-2000 | Custom widgets (grid editors, checkboxes) |
| 2000-4500 | MainWindow initialization, UI setup |
| 4500-8000 | Menu actions, file operations |
| 8000-12000 | Settings dialogs |
| 12000-18000 | Grid operations, navigation |
| 18000-25000 | Import/Export handlers |
| 25000-32000 | AI translation, batch operations |

### Key Classes

```python
@dataclass
class Project:
    segments: List[Segment]
    source_lang: str
    target_lang: str
    original_docx_path: Optional[str] = None
    memoq_source_path: Optional[str] = None
    sdlppx_source_path: Optional[str] = None
    phrase_source_path: Optional[str] = None
    original_txt_path: Optional[str] = None
    # ... 20+ fields total

@dataclass
class Segment:
    source: str
    target: str = ""
    status: str = "Not Started"
    notes: str = ""
    segment_type: str = "text"
    # ... additional fields
```

### File Extensions

| Extension | Purpose |
|-----------|---------|
| `.svproj` | Supervertaler project files (JSON) |
| `.svprompt` | Prompt files (JSON) |
| `.svntl` | Non-translatables lists (JSON) |

---

## 🔌 Complete Module List

### AI & LLM (`modules/`)
- `llm_clients.py` - OpenAI, Anthropic Claude, Google Gemini, Ollama, Custom OpenAI-Compatible API integration
- `model_version_checker.py` - Auto-detect new LLM models from providers
- `model_update_dialog.py` - UI for selecting new models
- `prompt_library.py` - Prompt management and favorites
- `prompt_assistant.py` - AI-powered prompt generation
- `unified_prompt_library.py` - Unified prompt system
- `unified_prompt_manager_qt.py` - Prompt manager UI
- `voice_dictation.py` - Whisper-based voice input
- `voice_commands.py` - Talon-style voice command system (NEW)
- `ai_actions.py` - AI action system for prompt library
- `ai_attachment_manager.py` - File attachment persistence
- `ai_file_viewer_dialog.py` - File viewing dialog

### Translation Memory & Terminology
- `translation_memory.py` - Fuzzy matching TM system
- `supermemory.py` - ChromaDB vector semantic search (2100+ lines)
- `termbase_manager.py` - SQLite-based terminology
- `term_extractor.py` - Automatic term extraction
- `termbase_entry_editor.py` - Term editing UI
- `termbase_import_export.py` - TMX/TBX import/export
- `tm_manager_qt.py` - TM management UI
- `tm_metadata_manager.py` - TM metadata handling
- `tm_editor_dialog.py` - TM editing dialog
- `tmx_editor.py` / `tmx_editor_qt.py` - TMX file editing
- `tmx_generator.py` - TMX file generation

### File Handlers
- `docx_handler.py` - Standard DOCX import/export
- `sdlppx_handler.py` - Trados Studio SDLPPX/SDLRPX packages (767+ lines)
- `phrase_docx_handler.py` - Phrase/Memsource bilingual DOCX
- `cafetran_docx_handler.py` - CafeTran bilingual DOCX
- `trados_docx_handler.py` - Trados bilingual review DOCX
- `dejavurtf_handler.py` - Déjà Vu X3 bilingual RTF (NEW in v1.9.91)
- `mqxliff_handler.py` - memoQ XLIFF files
- `simple_segmenter.py` - Text segmentation

### Spellcheck & QA
- `spellcheck_manager.py` - Dual-backend spellcheck (pyspellchecker + Hunspell)
- `non_translatables_manager.py` - Non-translatable term management
- `tag_cleaner.py` - CAT tool tag removal
- `tag_manager.py` - Tag handling

### UI Components
- `ribbon_widget.py` - Ribbon-style toolbar
- `translation_results_panel.py` - Match display panel
- `termview_widget.py` - Inline term display
- `superlookup.py` - Unified lookup window
- `superbrowser.py` - Multi-chat AI browser
- `quick_access_sidebar.py` - Quick access panel
- `keyboard_shortcuts_widget.py` - Shortcut management
- `project_home_panel.py` - Project home UI

### Utilities
- `database_manager.py` - SQLite database operations
- `database_migrations.py` - Database schema migrations
- `config_manager.py` - Settings management
- `file_dialog_helper.py` - File dialog utilities
- `find_replace.py` - Find and replace functionality
- `shortcut_manager.py` - Keyboard shortcut handling
- `theme_manager.py` - UI theme management
- `statuses.py` - Segment status definitions

### Specialized Tools
- `pdf_rescue_Qt.py` - AI OCR for PDF extraction
- `image_extractor.py` - Extract images from DOCX
- `figure_context_manager.py` - Image context for AI
- `document_analyzer.py` - Document analysis
- `encoding_repair.py` / `encoding_repair_Qt.py` - Fix encoding issues
- `autofingers_engine.py` - memoQ AutoFingers automation
- `tracked_changes.py` - Track changes analysis
- `supercleaner.py` / `supercleaner_ui.py` - Text cleaning

### Benchmarking
- `llm_leaderboard.py` - LLM quality benchmarking
- `superbench_ui.py` - Benchmark UI
- `local_llm_setup.py` - Ollama setup wizard

---

## 🏗️ Architecture Patterns

### UI Pattern
- PyQt6 with custom styled widgets
- Consistent styling:
  - Checkboxes: `CheckmarkCheckBox` (Standard), `PinkCheckmarkCheckBox` (Project), `BlueCheckmarkCheckBox` (Global)
  - Radio Buttons: `CheckmarkRadioButton` (Standard Green)
- Tag-based text formatting (`<b>`, `<i>`, `<u>`, `<li-o>`, `<li-b>`)
- Grid-based segment editor with source (read-only) and target (editable) columns

### Data Flow
1. Import file → Parse to segments → Display in grid
2. User translates/edits → Status updates → Grid refreshes
3. Export → Reconstruct original format with translations

### Settings Storage
- `settings/settings.json` - Unified configuration with `api_keys`, `general`, `ui`, and `features` sections
- `settings/` - Satellite files: `themes.json`, `shortcuts.json`, `recent_projects.json`, `find_replace_history.json`, `superlookup_history.json`, `voice_commands.json`, `model_version_cache.json`
- Legacy settings files are one-time migrated on startup and renamed to `.migrated`
- `.svproj` files - Per-project settings

---

## 📝 Development Guidelines

### When Editing Supervertaler.py
1. The file is large (~38K+ lines) - use line ranges when reading
2. Search for method names with `grep_search` before editing
3. Follow existing patterns for new features
4. `__version__` auto-reads from `pyproject.toml` (dev) or `importlib.metadata` (pip) — no manual update needed
5. To bump version: edit `pyproject.toml`, `CHANGELOG.md`, and `docs/index.html` (see Version Bump Checklist below)

### When Adding New Modules
1. Create in `modules/` directory
2. Add import in main file where needed
3. Follow existing module patterns (docstrings, type hints)

### Documentation Updates
**Always update these files after changes:**
1. `AGENTS.md` - Add dated entry to development history
2. `CHANGELOG.md` - Add version entry
3. `README.md` - Update version badge if needed

### Commit Messages
Use semantic prefixes:
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation
- `refactor:` - Code restructuring
- `style:` - Formatting

---

## ⚠️ Common Pitfalls

1. **ElementTree namespaces** - Always use namespace dict when working with SDLXLIFF:
   ```python
   NAMESPACES = {'sdl': 'http://sdl.com/FileTypes/SdlXliff/1.0'}
   element.find('.//sdl:seg', NAMESPACES)
   ```

2. **Grid widget access** - Use `table.cellWidget()` for QTextEdit, `table.item()` for QTableWidgetItem

3. **File paths** - Store absolute paths, use `os.path.exists()` before accessing

4. **Status updates** - Remember to update both internal data and grid display

5. **Signal blocking** - When setting text programmatically, use `blockSignals(True/False)` to prevent cascading events

6. **Qt event queue** - Be aware that `setPlainText()` queues events even when signals are blocked

7. **Hidden widget styling** - Qt may not apply stylesheets to hidden widgets. If theme colors aren't appearing, apply styles when the widget becomes visible, not just at creation time

8. **Race conditions & timing** - When debugging UI issues, consider whether the problem might be timing-related:
   - Widgets created before theme manager is initialized
   - Styles applied while widgets are hidden
   - Signals firing before handlers are connected
   - Use `QTimer.singleShot()` for deferred initialization when needed

---

## 📋 Planned Features & Refactoring

### 🔑 Inline API Key Editing in Settings UI (Completed in v1.9.240)

**Status:** Completed and released in v1.9.240

Users can now manage API keys directly in Settings > AI Settings with password-masked `QLineEdit` fields and show/hide toggles. Keys are read from and written to unified settings storage.

---

### 🔧 Configuration File Consolidation (Completed in v1.9.240)

**Status:** Completed and released in v1.9.240

Configuration was consolidated into `settings/settings.json` with four top-level sections:
- `api_keys`
- `general`
- `ui`
- `features`

The following files were also relocated under `settings/`: `themes.json`, `shortcuts.json`, `recent_projects.json`, `find_replace_history.json`, `superlookup_history.json`, `voice_commands.json`, and `model_version_cache.json`.

A one-time startup migration converts legacy files and renames originals to `.migrated`.

---

## � Future Investigation: TMX Tag Export Format


**Issue discovered December 22, 2025**: Our TMX Editor stores formatting tags (like `<b>`, `<i>`) as escaped text (`&lt;b&gt;`) in the `<seg>` element. This is valid XML but may not be the optimal approach.

**Three approaches exist:**

| Approach | Example in TMX file | Pros | Cons |
|----------|---------------------|------|------|
| **Escaped text** | `<seg>&lt;b&gt;text&lt;/b&gt;</seg>` | Simple, valid XML | Tags treated as plain text, lost semantic meaning |
| **TMX inline elements** | `<seg><bpt i="1" type="bold">&lt;b&gt;</bpt>text<ept i="1">&lt;/b&gt;</ept></seg>` | TMX 1.4 compliant, preserves tag semantics | More complex to implement |
| **Raw XML** (invalid) | `<seg><b>text</b></seg>` | Human readable | Invalid XML unless DTD defines `<b>` |

**What other tools do:**
- **memoQ**: Uses TMX inline elements (`<bpt>`, `<ept>`) for proper tag preservation
- **Trados Studio**: Similar, uses inline elements with type attributes
- **OmegaT**: Generally uses escaped text for simplicity
- **Many web tools**: Just escape everything

**Recommendation for future**: Consider implementing proper TMX inline elements (`<bpt>`, `<ept>`, `<ph>`) when exporting. This would:
1. Maintain compatibility with professional CAT tools
2. Preserve tag type information (bold, italic, etc.)
3. Allow round-tripping without tag loss

**Files to modify**: `modules/tmx_editor.py` - `TmxParser.save_file()` method

---

## �💡 Problem-Solving Tips for AI Agents

When stuck on a difficult bug, consider these approaches:

1. **Think about timing**: Is this a race condition? Are things happening in the wrong order?
   - Widget creation vs. theme application timing
   - Signal connections vs. signal emissions
   - Hidden vs. visible widget state changes

2. **Think outside the box**: The obvious solution may not work
   - If stylesheets aren't applying, try QPalette as an alternative
   - If a method isn't being called, check if the widget is even visible
   - If changes aren't reflected, check if there's caching involved

3. **Add debug output**: When behavior is mysterious, add logging to trace execution flow
   - Print method entry/exit with timestamps
   - Log parameter values and state
   - Write to a debug file if console output is too fast

4. **Question assumptions**: What do you THINK is happening vs. what is ACTUALLY happening?
   - The code might be running but not having the expected effect
   - A different code path might be executing
   - Something else might be overriding your changes

---

## 🧪 Testing

### Running Tests
```bash
pytest tests/
```

### Manual Testing Checklist
- [ ] Import DOCX, translate segment, export
- [ ] Save/load .svproj project
- [ ] TM matching works
- [ ] Termbase highlighting works
- [ ] AI translation (if API keys configured)
- [ ] Spellcheck toggles correctly
- [ ] SDLPPX import/export round-trip

---

## 🔑 API Keys

**Unified Settings Storage (v1.9.240+):**

API keys are stored in `settings/settings.json` under the `api_keys` section.

| Platform | Default Data Folder | API Key Storage |
|----------|---------------------|-----------------|
| **All Users (default)** | `~/Supervertaler/` | `settings/settings.json` → `api_keys` |
| **Windows (default)** | `C:\Users\Username\Supervertaler\` | `settings\settings.json` → `api_keys` |
| **Development** | `user_data_private\` (git-ignored) | `settings\settings.json` → `api_keys` |

**Backward compatibility:**
- Legacy `api_keys.txt` remains supported as a fallback input path.
- New writes persist to `settings/settings.json`.

**Supported keys:**
- `openai`, `claude`, `google`, `gemini`, `custom_openai`, `deepl`, `google_translate`, `ollama_endpoint`

**Notes:**
- `google` and `gemini` are aliases.
- `custom_openai` is for OpenAI-compatible endpoints; endpoint/model are configured in Settings > AI Settings.
- `ollama_endpoint` can override the default (`http://localhost:11434`).

---

## 🔄 Recent Development History

### February 8, 2026 - Unified Settings + Inline API Key Editing (v1.9.240)

**✨ Feature Summary**

Completed the unified settings migration and inline API key editing workflow.

**Status:** Implementation complete, version 1.9.240 released to PyPI

**Highlights:**
- Consolidated core settings into `settings/settings.json` with `api_keys`, `general`, `ui`, and `features` sections
- Added password-masked API key fields with show/hide toggles in Settings > AI Settings
- Implemented one-time startup migration that renames legacy files to `.migrated`
- Moved satellite settings/history files into the `settings/` subfolder
- Removed dead code for deprecated settings paths

---


### February 7, 2026 - Custom OpenAI-Compatible API Provider (v1.9.236)

**✨ Feature Summary**

Added a generic "Custom (OpenAI-Compatible API)" provider that enables any OpenAI SDK-compatible endpoint — Volcengine (ByteDance Doubao), Alibaba Tongyi (Qwen), DeepSeek, Mistral, Groq, and more. This addresses GitHub issue #155 requesting Chinese AI services that handle Chinese translation better.

**Status:** Implementation complete, version 1.9.236 released to PyPI

**Issue Addressed:**
- GitHub #155 - Feature request for Volcengine (Doubao) and Tongyi (Qwen) support

**Approach:**
Rather than adding each Chinese AI provider individually, implemented a single `custom_openai` provider that reuses `_call_openai()` with a user-specified `base_url`. Users configure: endpoint URL, API key (in `api_keys.txt` as `custom_openai = <key>`), and model name (free-text input since model names vary by provider).

**Files Modified:**

1. **`modules/llm_clients.py`**:
   - Added `base_url: Optional[str] = None` parameter to `__init__`
   - `translate()` routes `"custom_openai"` to `_call_openai()` (same as `"openai"`)
   - `_call_openai()` passes `base_url` to `OpenAI()` constructor when set
   - `DEFAULT_MODELS` includes `"custom_openai": "custom-model"`
   - `load_api_keys()` includes `"custom_openai": ""` in defaults
   - API key validation skipped for `custom_openai` (some endpoints don't need one)

2. **`Supervertaler.py`** — Settings UI:
   - Added `custom_radio = CustomRadioButton("🔌 Custom (OpenAI-Compatible API)")` in `_create_ai_settings_tab()`
   - Added `custom_endpoint_input` (QLineEdit for URL) and `custom_model_input` (QLineEdit for model name)
   - Added `custom_enable_cb = CheckmarkCheckBox("Enable Custom (OpenAI-Compatible)")`
   - Save handler (`_save_ai_settings_from_ui()`) saves `custom_openai_model`, `custom_openai_endpoint`
   - `load_llm_settings()` includes `custom_openai_model` and `custom_openai_endpoint` defaults
   - `load_provider_enabled_states()` includes `llm_custom_openai: True`

3. **`Supervertaler.py`** — Helper method:
   - Added `create_llm_client(provider, model, api_keys, settings)` method that handles `base_url` logic in one place
   - Used at ~12 `LLMClient()` instantiation points to avoid duplicating custom_openai logic
   - `PreTranslationWorker` accepts `base_url` parameter for batch translation

4. **`modules/quicktrans.py`**:
   - Added `("Custom", "CUS", "custom_openai", "mtql_custom_openai")` to `llm_defs`
   - `_call_llm_translation()` handles base_url for custom_openai, reads endpoint from parent_app settings

5. **`user_data_private/api_keys.example.txt`**: Added `custom_openai` section with example endpoints

**LLM Provider Architecture (5 providers total):**
- `openai` — OpenAI GPT models
- `claude` — Anthropic Claude models
- `gemini` — Google Gemini models
- `ollama` — Local Ollama models (no API key needed)
- `custom_openai` — Any OpenAI-compatible endpoint (reuses `_call_openai()` with custom `base_url`)

**Settings stored in `settings/settings.json` (`ui` section):**
- `llm_settings.provider` — active provider name
- `llm_settings.custom_openai_model` — model name or endpoint ID
- `llm_settings.custom_openai_endpoint` — base URL (e.g., `https://ark.cn-beijing.volces.com/api/v3/`)
- `provider_enabled_states.llm_custom_openai` — enabled toggle

---

### February 7, 2026 - Version Display Fix for pip Users (v1.9.235)

**🐛 Bug Fix**

Fixed `_read_version()` which caused all pip-installed users to see version 1.9.227 regardless of the actual installed version. The function only tried `pyproject.toml` (which isn't included in pip wheels) and had a hardcoded fallback. Now uses a two-step approach:
1. Try `pyproject.toml` via `tomllib` (works in dev/source checkout)
2. Try `importlib.metadata.version("supervertaler")` (works after pip install)
3. Fallback to `"0.0.0"` instead of a misleading real version number

---

### February 7, 2026 - Multi-file Export & Batch Fixes (v1.9.232-234)

**✨ Features:**
- **Multi-file export "Original Format" option** (v1.9.234): Exports each file back to its source format (`.txt`, `.md`, or `.docx`), useful for mixed-format projects
- **Saved Views** (v1.9.232): Named views that filter the grid to selected files, persisted in project file
- **File boundary separators** (v1.9.232): Blue separator lines between files in multi-file projects
- **Markdown in multi-file import** (v1.9.232): `.md` files recognized alongside `.docx` and `.txt`
- **Tabbed Project Info dialog** (v1.9.232): Overview and File Progress tabs merged into one dialog

**🐛 Bug Fixes:**
- **Batch pre-translation SQLite thread error** (v1.9.233): Worker thread was calling main thread's SQLite connection for AI-inject glossary terms. Terms now pre-fetched on main thread and passed to worker.

---

### February 7, 2026 - memoQ RTF Fixes & UI Improvements (v1.9.228-231)

**🐛 Bug Fixes:**
- **memoQ RTF Unicode/formatting loss** (v1.9.231): Unicode escapes and RTF character control words were stripped by the generic cleanup regex. All Unicode escapes, hex escapes, and named character control words now decoded before the generic strip.
- **memoQ RTF combined formatting** (v1.9.231): Segments with bold+underline lost all formatting. Replaced pair-matching regex with direct marker-to-tag conversion.
- **memoQ RTF missing import options dialog** (v1.9.231): RTF import now shows the same formatting options dialog as DOCX import.
- **TM Read/Write settings persistence** (v1.9.228): Stale global TM activations could override project-specific settings on restart. Project-specific settings now always take priority.

**🎨 UI Improvements:**
- **Settings panel reorganized** (v1.9.227): AI Translation Preferences section reorganized with sub-headings
- **Version auto-read from pyproject.toml** (v1.9.227): `__version__` no longer needs manual updates

---

### February 6, 2026 - WYSIWYG Fix & Import Language Memory (v1.9.224-226)

**🐛 Bug Fixes:**
- **WYSIWYG/Tags toggle corrupted target text** (v1.9.225, #142): View mode toggle permanently destroyed whitespace/indentation. Fixed with `white-space: pre-wrap` CSS and `_suppress_target_change_handlers` guard.
- **Import dialogs ignored saved language pair** (v1.9.226, #143): Text/Markdown and multi-file import dialogs always defaulted to English → Dutch. Now all three import dialogs share language memory via `general_settings.json`.

---

### February 6, 2026 - memoQ Bilingual RTF Support (v1.9.223)

**✨ Feature Summary**

Added full import/export support for memoQ bilingual RTF files, addressing GitHub issue #145. This enables users with older memoQ versions (or those who prefer RTF format) to use the same bilingual table workflow as DOCX.

**Status:** Implementation complete, version 1.9.223 released

**Issue Addressed:**
- GitHub #145 - Feature request for memoQ RTF bilingual file support

**Implementation Details:**

The memoQ RTF bilingual format uses the identical 5-column table structure as memoQ DOCX:
- Column 1: Segment ID (number + GUID)
- Column 2: Source text (with formatting)
- Column 3: Target text
- Column 4: Comments
- Column 5: Status ("Not started", "Edited", "Confirmed", etc.)

**New Module - `modules/memoqrtf_handler.py`:**

```python
class MemoQRTFHandler:
    """Handler for memoQ bilingual RTF files."""

    def load(self, file_path: str) -> bool:
        """Load and parse memoQ bilingual RTF."""

    def save(self, output_path: str) -> bool:
        """Save RTF with updated translations."""

    def get_source_texts(self) -> List[str]:
        """Get source segments for translation."""
```

**Key Features:**
- Parses RTF table structure using `\cell` and `\row` markers
- Handles RTF formatting codes (`\b` bold, `\i` italic, `\ul` underline)
- Decodes Unicode escapes (`\uNNNN?`) and hex character codes (`'XX`)
- Preserves RTF structure for clean round-trip export
- Auto-detects source/target languages from header row

**Menu Integration:**
- Import: File → Import → memoQ Bilingual Table (RTF)...
- Export: File → Export → memoQ Bilingual Table - Translated (RTF)...

**Files Modified:**

1. **`modules/memoqrtf_handler.py`** (NEW):
   - `MemoQRTFHandler` class for parsing/saving memoQ RTF
   - `MemoQSegment` dataclass for segment representation
   - RTF escape/decode utilities
   - Language detection from header row

2. **`Supervertaler.py`**:
   - Added menu actions for memoQ RTF import/export (lines ~8165, ~8226)
   - Added `import_memoq_rtf()` method (lines ~27679-27805)
   - Added `export_memoq_rtf()` method (lines ~28407-28515)
   - Stores `memoq_rtf_source_path` in project for persistence

**Technical Notes:**
- RTF parsing uses regex to find cell content between `\cell` markers
- Unicode handling: `\uc0\uNNNN` and `\uNNNN?` patterns
- Negative Unicode values converted per RTF spec: `code + 65536`
- Target cell replacement done in reverse order to preserve positions

---

### February 5, 2026 - Custom Tooltips & Clean Slate Project Imports (v1.9.222)

**✨ Feature Summary**

Fixed black tooltip rendering issue on certain systems by implementing custom tooltip widgets. Also clarified and restored the "clean slate" behavior for new project imports.

**Status:** Implementation complete, version 1.9.219 released

**Issues Addressed:**
- Black tooltip rectangles when hovering over status icons (PyQt6/Qt tooltip rendering issue)
- GitHub #140 investigation ongoing (TM not readable after re-import on macOS)

**Custom Tooltip Implementation:**

Qt's built-in `QToolTip` rendered as black rectangles on some systems due to platform-specific styling issues. Solution: bypass Qt's tooltip system entirely with custom `QLabel` popup widgets.

**Key Code - Custom Tooltip Widget** (`Supervertaler.py`):
```python
def _get_custom_tooltip(self):
    """Get or create the custom tooltip label widget."""
    if not hasattr(self, '_custom_tooltip') or self._custom_tooltip is None:
        self._custom_tooltip = QLabel()
        self._custom_tooltip.setWindowFlags(
            Qt.WindowType.ToolTip | Qt.WindowType.FramelessWindowHint
        )
        self._custom_tooltip.setStyleSheet("""
            QLabel {
                background-color: #f5f5f5;
                color: #333333;
                border: 1px solid #d0d0d0;
                padding: 4px 8px;
                font-size: 12px;
            }
        """)
        self._custom_tooltip.hide()
    return self._custom_tooltip
```

**Event Filter for Status Icons:**
- Intercepts `QEvent.Type.ToolTip` events on status icon labels
- Shows custom tooltip popup instead of Qt's default
- Hides popup on `QEvent.Type.Leave`

**Clean Slate Project Imports (Design Clarification):**

The `_deactivate_all_resources_for_new_project()` function ensures new projects start with a clean slate:
- **Design Intent:** When importing a new document, NO TMs or glossaries should be pre-selected
- **User Workflow:** Import document → Select only needed TMs/glossaries → Work with relevant resources
- This prevents resource "pollution" from previous projects carrying over

**Files Modified:**

1. **`Supervertaler.py`**:
   - Added `_get_custom_tooltip()` method for creating styled tooltip widgets
   - Added `_show_status_tooltip()` and `_hide_status_tooltip()` methods
   - Event filter on status icon labels to intercept tooltip events
   - Confirmed `_deactivate_all_resources_for_new_project()` deactivates resources (clean slate)

2. **`modules/theme_manager.py`**:
   - Added QToolTip styling in stylesheet (#f5f5f5 background, #333333 text)
   - Added QPalette tooltip colors as fallback for Qt versions that ignore stylesheet

**Tooltip Color Choice:**
- Background: `#f5f5f5` (light gray) - professional, readable in all themes
- Text: `#333333` (dark gray) - high contrast
- Border: `#d0d0d0` - subtle definition

**GitHub #140 Investigation Notes:**

Bug report indicates TM not readable after re-importing document on macOS:
- Checkbox appeared checked but TM wasn't being searched
- Workaround: Uncheck, restart, recheck
- **Hypothesis:** When re-importing creates a new project_id, the TM activation records from the old project_id don't apply
- **Awaiting clarification** from bug reporter on exact workflow

---

### February 1, 2026 - Dark Mode Refinements & UI Improvements

**✨ Feature Summary**

Improved dark mode text visibility and fixed TM navigation arrows that were invisible or rendering incorrectly across light and dark themes.

**Status:** Implementation complete, version 1.9.184 released

**Files Modified:**

1. **`Supervertaler.py`** - Multiple UI improvements:
   - TermView source text color: Changed to #FFFFFF in dark mode for better contrast (lines 175, 456)
   - HTML tag colors: Light pink (#FFB6C1) in dark mode for `<b>`, `</b>` tags (lines 1403-1413, 2733-2743)
   - Navigation arrows: Implemented ClickableArrow class with Unicode symbols (◀ ▶) and theme-aware colors (lines 29674-29733)
   - Table header font: Reduced from `font_size + 1` to `font_size` for better proportions (line 30834)
   - Theme refresh: Added arrow color updates in `refresh_theme_colors()` (lines 43993-43999)

2. **`modules/unified_prompt_manager_qt.py`** - Fixed Issue #112:
   - Prompt edits now immediately reflected in Prompt Library and Preview Combined
   - Cache refresh for both active primary and attached prompts (lines 2377-2384)

3. **`build_windows_release.ps1`** - Added Start Menu shortcut scripts to release packages (lines 111-116)

4. **`create_release_zip.py`** - Added shortcut creation instructions to README (lines 28-31)

**Key Code Locations:**

**ClickableArrow Class** (Supervertaler.py:29684-29705):
```python
class ClickableArrow(QLabel):
    clicked = pyqtSignal()

    def __init__(self, arrow_symbol, parent=None):
        self.arrow_symbol = arrow_symbol
        super().__init__("", parent)
        self.setCursor(Qt.CursorShape.PointingHandCursor)

    def set_color(self, color):
        """Update arrow color for current theme"""
        self.setStyleSheet(f"""
            QLabel {{
                color: {color};
                background: transparent;
                border: none;
                font-size: 11px;
                font-weight: bold;
            }}
        """)
        self.setText(self.arrow_symbol)
```

**Theme Color Logic:**
- Dark mode: White arrows (#FFFFFF), light pink tags (#FFB6C1)
- Light mode: Dark gray arrows (#333333), standard tag colors

**Development Notes:**

- Initially tried PNG arrow images but they rendered fuzzy
- Attempted Unicode angle brackets (❮ ❯) but font support was inconsistent
- Final solution: Unicode triangle symbols (◀ ▶) render crisply on all systems
- Arrow visibility issues were caused by arrows being created at startup before theme was applied
- Solution: ClickableArrow class with `set_color()` method called during theme refresh

**PowerShell Scripts Created:**
- `create_start_menu_shortcut.ps1` - For end users (Supervertaler.exe)
- `create_dev_start_menu_shortcut.ps1` - For developers (run.cmd)

**Related Issues:**
- Fixed #112: Prompt editing bug where saved prompts weren't updating in UI

---

### January 30-31, 2026 - Total Recall Architecture & Build System Unification

**✨ Feature Summary**

Implemented CafeTran-inspired "Total Recall" architecture for instant grid navigation. Instead of querying giant TMs on every segment click, relevant segments are extracted into lightweight in-memory structures on project load.

**Status:** Implementation complete, ready for testing

**Files Created:**

1. **`modules/project_tm.py`** - In-memory TM for instant lookups
2. **`modules/extract_tm.py`** - Persistent TM extraction to .svtm files

**Files Modified:**

1. **`Supervertaler.py`** (~938 lines changed)
2. **`modules/database_manager.py`** - Reduced candidate limit
3. **`build_windows_release.ps1`** - Unified build system

---

#### Implementation 1: In-Memory Termbase Index (Quick Win)

On project load, buil

…(truncated)
