# 075 Agents 125bbbb5

> Supervertaler - AI Agent Documentation

- Skill: `tools-only/075-agents-125bbbb5` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/075-agents-125bbbb5`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/075-agents-125bbbb5/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/075-agents-125bbbb5

---

# Supervertaler - AI Agent Documentation

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

---

## ⚡ 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.223** - memoQ RTF bilingual support, TM fixes
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.223 (memoQ RTF support)
- **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.223 (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` (~38,000+ lines) |
| **Modules** | 60+ specialized modules in `modules/` directory |

### Key Capabilities

- **Multi-LLM AI Translation**: OpenAI GPT-4, Anthropic Claude, Google Gemini, Local Ollama
- **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 (~38,000+ lines)
├── modules/                   # 60+ 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 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
- `user_data/general_settings.json` - App preferences
- `user_data/ui_preferences.json` - Window geometry, button states
- `.svproj` files - Per-project settings

---

## 📝 Development Guidelines

### When Editing Supervertaler.py
1. The file is large (~32K lines) - use line ranges when reading
2. Search for method names with `grep_search` before editing
3. Follow existing patterns for new features
4. Update `__version__` at the top when making changes

### 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

### 🔧 Configuration File Consolidation (PRIORITY - Scheduled)

**Identified:** January 9, 2026  
**Status:** Documented, not yet implemented  
**Complexity:** Medium (30-40 file edits + migration script)

**Current Problem: Configuration File Sprawl**

Settings are currently scattered across multiple JSON files in `user_data/`:
- `general_settings.json` - General application preferences
- `ui_preferences.json` - Window geometry, button states (DEPRECATED, migrated to general_settings.json)
- `themes.json` - Theme definitions
- `recent_projects.json` - Recent project list
- `feature_settings.json` - Optional feature toggles
- `find_replace_history.json` - Find & Replace history
- `superlookup_history.json` - Superlookup search history
- `voice_commands.json` - Voice command library
- Plus module-specific configs...

**Issues:**
1. **Scattered settings** - Hard to find where a setting is stored
2. **Code complexity** - Multiple file read/write operations throughout codebase
3. **Inconsistent structure** - Each file has different patterns (nested vs flat, etc.)
4. **Migration headaches** - Changing structure requires updating multiple files
5. **User confusion** - Manual editing requires knowing which file to look in
6. **Backup/restore complexity** - Must backup multiple files to preserve all settings

**Proposed Solution: Single `config.json`**

Consolidate all settings into one well-structured file:

```json
{
  "config_version": "1.0.0",
  "general": {
    "restore_last_project": false,
    "auto_propagate_exact_matches": true,
    "auto_center_active_segment": true,
    "auto_insert_100_percent_matches": true,
    "auto_confirm_100_percent_matches": false,
    "tm_save_mode": "latest",
    "enable_smart_word_selection": true,
    "enable_auto_backup": true,
    "backup_interval_minutes": 5
  },
  "ui": {
    "theme": "light",
    "window_geometry": {
      "x": 100,
      "y": 100,
      "width": 1200,
      "height": 800
    },
    "fonts": {
      "grid_family": "Segoe UI",
      "grid_size": 11,
      "results_match_size": 9,
      "results_compare_size": 9,
      "termview_family": "Segoe UI",
      "termview_size": 10,
      "termview_bold": false
    },
    "colors": {
      "tag_color": "#7f0001",
      "focus_border_color": "#2196F3",
      "focus_border_thickness": 2,
      "badge_text_color": "#333333",
      "invisible_char_color": "#999999",
      "even_row_color": "#FFFFFF",
      "odd_row_color": "#F0F0F0"
    },
    "layout": {
      "tabs_above_grid": false,
      "enable_alternating_row_colors": true,
      "show_invisibles": false
    }
  },
  "features": {
    "supermemory_enabled": true,
    "supermemory_auto_init": false,
    "voice_enabled": false,
    "web_browser_enabled": true,
    "pdf_rescue_enabled": true,
    "autofingers_enabled": false
  },
  "match_limits": {
    "LLM": 3,
    "MT": 5,
    "TM": 10,
    "Termbases": 10
  },
  "termbase": {
    "enable_grid_highlighting": true,
    "highlight_style": "semibold",
    "display_order": "appearance",
    "hide_shorter_matches": false,
    "dotted_color": "#808080"
  },
  "precision_scroll": {
    "divisor": 3
  },
  "recent_projects": [
    "/path/to/project1.svproj",
    "/path/to/project2.svproj",
    "/path/to/project3.svproj"
  ],
  "custom_themes": [
    {
      "name": "Dark Blue",
      "is_dark": true,
      "colors": {
        "background": "#1e1e1e",
        "foreground": "#d4d4d4",
        ...
      }
    }
  ],
  "history": {
    "find_replace": [
      {"find": "example", "replace": "sample"}
    ],
    "superlookup_searches": [
      "translation memory",
      "terminology"
    ]
  },
  "voice_commands": {
    "enabled": false,
    "recognition_engine": "openai_whisper",
    "custom_commands": [
      {
        "phrase": "next segment",
        "aliases": ["go next", "move forward"],
        "action_type": "internal",
        "action": "next_segment"
      }
    ]
  },
  "ollama": {
    "keepwarm": false
  },
  "autohotkey": {
    "path": "C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe"
  }
}
```

**Benefits:**
- ✅ **Single source of truth** - All settings in one place
- ✅ **Clear hierarchy** - Logical grouping by functionality
- ✅ **Easy to read/edit** - Clear structure for manual editing
- ✅ **Atomic saves** - All settings updated together (no partial updates)
- ✅ **Simple backup/restore** - One file to backup
- ✅ **Version tracking** - `config_version` field for migrations
- ✅ **Better defaults** - Easy to see all default values at once

**Implementation Plan:**

1. **Create `modules/config_manager_v2.py`** (new unified config manager):
   - `ConfigManager` class with section accessors
   - `get(section, key, default)` method
   - `set(section, key, value)` method
   - `save()` method (atomic write)
   - `load()` method with validation

2. **Migration script** (`scripts/migrate_config.py`):
   - Read all existing JSON files
   - Map to new structure
   - Write `config.json`
   - Backup old files to `user_data/config_backup/`
   - Run automatically on first startup after update

3. **Update all load/save calls** (~30-40 locations):
   - Replace `_load_general_settings_from_file()` → `config_manager.get('general', key)`
   - Replace `save_general_settings()` → `config_manager.set('general', key, value)` + `config_manager.save()`
   - Update theme manager
   - Update recent projects
   - Update find/replace history
   - Update voice command loader

4. **Backward compatibility**:
   - Keep old loaders as fallback for 1-2 versions
   - Log migration warnings
   - Auto-migrate on first run

5. **Testing checklist**:
   - [ ] Fresh install (no config files)
   - [ ] Migration from old files
   - [ ] Settings persist correctly
   - [ ] All features still work
   - [ ] No performance regression

**Files to modify:**
- `Supervertaler.py` - Replace all config load/save calls
- `modules/config_manager_v2.py` - NEW unified config manager
- `modules/theme_manager.py` - Use new config manager
- `modules/voice_commands.py` - Use new config manager
- `modules/find_replace_qt.py` - Use new config manager
- `scripts/migrate_config.py` - NEW migration script

**Estimated effort:** 3-4 hours (careful testing needed)

**Priority:** High (improves maintainability significantly)

---

## � 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 Loading System with Persistent Storage:**

API keys are stored in the persistent user data location (see Installation section).

**User Data Locations (v1.9.148+):**

| Platform | Default Data Folder | API Keys File |
|----------|---------------------|---------------|
| **All Users (default)** | `~/Supervertaler/` | `~/Supervertaler/api_keys.txt` |
| **Windows (default)** | `C:\Users\Username\Supervertaler\` | `...\Supervertaler\api_keys.txt` |
| **Development** | `user_data_private\` (git-ignored) | `user_data_private\api_keys.txt` |

**Note:** Users can choose their own data folder location on first run or via Settings → General → Data Folder Location.

**For Developers (running from source):**
- Store keys in: `user_data_private/api_keys.txt`
- This location is fully gitignored and will **never** be uploaded to GitHub
- All features (translation, AI Assistant, tests) will find keys here

**For End Users (pip install):**
- On first run, choose where to store your data (default: `~/Supervertaler/`)
- Store API keys in: `[your-data-folder]/api_keys.txt`
- The app prints the exact path on startup: `[Data Paths] User data: ...`
- Keys persist across pip upgrades!

**For Windows EXE Users:**
- Same as pip users - choose your data folder on first run
- Default is visible in your home folder: `C:\Users\Username\Supervertaler\`

**Format:**
```
openai=sk-...
claude=sk-ant-...
google=AI...
gemini=AI...
deepl=...
```

**Note:** `google=` and `gemini=` are aliases - both work identically (v1.9.146+).

**Implementation Details:**
- `Supervertaler.py`: `load_api_keys()` method reads from user_data_path
- Automatic normalization: if `google` is set, `gemini` is also populated (and vice versa)
- All API key loading now unified through main app's method

---

## 🔄 Recent Development History


### 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, builds a Python dict mapping `lowercase_word -> [term_info, ...]` for O(1) termbase lookups.

**Key code locations in Supervertaler.py:**
- `self.termbase_index` initialization: ~line 6243
- `_build_termbase_index()`: ~line 22502
- `_search_termbase_index()`: ~line 22645
- Integration (called on project load): ~line 22265

---

#### Implementation 2: ProjectTM - In-Memory TM

**File:** `modules/project_tm.py`

On project load, extracts relevant TM segments (fuzzy matches ≥75%) into an in-memory SQLite database with FTS5 for fast fuzzy search.

**Features:**
- `ProjectTM` class with in-memory SQLite + FTS5
- `extract_from_database()` - extracts segments matching project content
- `search()` - instant lookup (exact match first, then FTS5 fuzzy)
- Thread-safe with locking

**Integration in Supervertaler.py:**
- `self.project_tm` initialization: ~line 6250
- Progress signal: `_project_tm_progress_signal` at ~line 6128
- Background extraction: `_start_project_tm_extraction_background()` at ~line 7553
- UI indicator in status bar: `self.project_tm_indicator` at ~line 7439

---

#### Implementation 3: ExtractTM - Persistent TM Extraction

**File:** `modules/extract_tm.py`

Extracts relevant segments from selected TMs into a `.svtm` file (SQLite) that persists across sessions.

**Features:**
- `ExtractTM` class with persistent SQLite storage
- `extract_and_save()` - extracts and saves to file
- `load()` - loads existing extraction
- `search()` - fast lookup with FTS5
- `export_to_tmx()` - export to standard TMX format
- File saved as `{Pro

…(truncated)
