Skip to content

Coding Instructions for AI Agents

GehaSoftwareHub - Project Standards & Best Practices


Purpose

This document provides clear instructions for AI coding agents (Claude Code, GitHub Copilot, etc.) working on this project. Following these guidelines ensures consistent, high-quality code that adheres to project standards.

Before writing ANY code, review this document and the referenced guides.


Core Principles

"Write code that is correct, maintainable, well-documented, and testable - in that order."

Quality over speed. Readable over clever. Explicit over implicit.


Required Reading: Project Guides

Read these guides BEFORE writing code (located in docs/dev_guidelines/):

  1. python_style_guide.md - PEP 8 compliance, naming, imports. CRITICAL
  2. pyside6_architecture_guide.md - Signal/Slot, MVC, threading, memory. CRITICAL for PySide6 code
  3. refactoring_import_guide.md - Import migration rules (src/ only). CRITICAL during refactor
  4. path_management_guide.md - PathDef system, get_path()/get_path_str(). HIGH
  5. constants_management_guide.md - Magic numbers, enums, config. HIGH
  6. file_operations_guide.md - Atomic file I/O, thread safety. HIGH
  7. pragmatic_testing_guide.md - What/how to test. HIGH
  8. python_documentation_guide.md - Google style docstrings, type hints. HIGH

Project-Specific Rules (CLAUDE.md)

These rules are non-negotiable and override any generic best practice:

Language Rules

  • User-facing text: Always in German. Use direct umlauts: o, a, u (never oe, ae, ue)
  • Code comments: Always in English
  • Docstrings: Always in English (Google style)

Code Rules

  • No Unicode symbols: Use text-based indicators instead. Not even in test scripts
  • Empty __init__.py files: Never put any code in __init__.py
  • No hardcoded QSS stylesheets: Give every UI element a meaningful .setObjectName(). Styling is handled externally via StylesheetManager
  • Logger: Always local import of get_logger(), never global
# CORRECT - Local import
def some_method(self) -> None:
    from src.shared_services.logging.logger_factory import get_logger
    logger = get_logger()
    logger.debug("Something happened")

# WRONG - Global import
from src.shared_services.logging.logger_factory import get_logger
logger = get_logger()  # Never at module level
  • Tooltips: Use sparingly, only when truly beneficial. Prefer descriptive button/label names
  • File operations: Follow file_operations_guide.md strictly

Project Architecture

Directory Structure

GehaSoftwareHub/
+-- src/                              # All refactored source code
|   +-- custom_widgets/               # Reusable UI widgets
|   |   +-- constants/
|   |   +-- controls/                 # SmartBackButton, etc.
|   |   +-- dialogs/                  # User guide dialog, etc.
|   |   +-- feedback/                 # Feedback widgets
|   |   +-- widget_handlers/          # Splitter, stacked widget managers
|   |
|   +-- main_hub/                     # Main application
|   |   +-- features/                 # Feature modules (MVC each)
|   |   |   +-- home_system/          # Home dashboard
|   |   |   |   +-- bound_subsystems/ # GitHub issues, milestones
|   |   |   +-- settings_system/      # Application settings
|   |   |   +-- software_system/      # Software selection hub
|   |   |   +-- update_system/        # Auto-update system
|   |   |   +-- user_guide_system/    # User guide
|   |   +-- orchestration/            # Main app coordination
|   |   |   +-- constants/            # View indices, etc.
|   |   |   +-- controller/           # MainController
|   |   |   +-- view/                 # MainView
|   |   +-- ux_testing_environment/   # Developer testing tools
|   |
|   +-- shared_services/              # Shared infrastructure
|       +-- cloud_com/                # Cloud communication
|       |   +-- github_com/           # GitHub API client
|       |   +-- r2_com/              # R2 storage
|       +-- constants/                # App constants, PathDef definitions
|       +-- file_operations/          # Atomic file I/O (JSON, msgpack, text)
|       +-- logging/                  # AsyncAppLogger
|       +-- path_management/          # PathDef resolution system
|       +-- prompt_dialogs/           # Dialog system (info, warning, error, input)
|       +-- rendering/               # Visual rendering
|       |   +-- documents/            # Markdown/document rendering
|       |   +-- icons/                # IconRegistry, SVG rendering
|       |   +-- stylesheets/          # StylesheetManager, theme system
|       +-- security/                 # OAuth, encryption, login
|       +-- settings/                 # SettingsManager
|       +-- state/                    # AppState singleton
|       +-- utils/                    # Shared utilities
|
|   +-- modules/                      # Domain modules
|       +-- plant_design/             # Plant design module
|           +-- startup_system/       # Project launcher, library management
|           +-- zentral_systems/      # Shared systems (library, planning, schema, etc.)
|           +-- pd_runtime_system/    # Runtime stages (planning, engineering, etc.)
|
+-- data/
|   +-- .app_data/                    # App resources (REPLACEABLE on update)
|   |   +-- icons/                    # SVG icons
|   |   +-- stylesheets/             # QSS stylesheets per module
|   +-- persistent_data/              # User data (PROTECTED on update)
|
+-- docs/
    +-- dev_guidelines/               # This directory

Architecture Pattern: MVC

Each feature module follows Model-View-Controller separation:

feature_system/
+-- controller/          # Coordinates model and view
+-- model/               # Business logic, data (optional)
+-- view/                # UI widgets
|   +-- pyui/            # Auto-generated Python from .ui files
|   +-- ui/              # Qt Designer .ui files
+-- constants/           # Feature-specific constants (optional)
+-- paths.py             # Feature-specific PathDef definitions

Rules: 1. Models: Pure business logic. Only QObject/Signal from PySide6 2. Views: UI only, emit signals for user actions. No business logic 3. Controllers: Coordinate models and views, handle application logic


Import Patterns

All refactored code must import from src/ only

# Standard library
from typing import Optional, List

# Third-party
from PySide6.QtCore import QObject, Signal, Slot
from PySide6.QtWidgets import QWidget

# Local application (always absolute from src.)
from src.shared_services.rendering.icons.api import IconRegistry, Icons, IconColors
from src.shared_services.rendering.stylesheets.api import StylesheetManager
from src.shared_services.prompt_dialogs.api import show_info, show_warning
from src.shared_services.file_operations.api import save_json, load_json
from src.shared_services.state.app_state import AppState

See refactoring_import_guide.md for the complete migration table.


Key Project Systems

1. Icons - IconRegistry (Theme-Aware)

from src.shared_services.rendering.icons.api import IconRegistry, Icons, IconColors

# Primary API: Register for automatic theme updates
registry = IconRegistry.instance()
registry.register(my_button, Icons.Action.Save, color=IconColors.Primary)

# For QLabels, use as_pixmap=True
registry.register(my_label, Icons.Status.Info, color=IconColors.Primary, as_pixmap=True)

# For dynamic icons, unregister before re-registering
registry.unregister(my_button)
registry.register(my_button, Icons.Action.Edit, color=IconColors.Accent)

Important: render_svg() and set_widget_icon() are low-level and do NOT update on theme change. Use IconRegistry.register() as the primary API.

2. Stylesheets - StylesheetManager

from src.shared_services.rendering.stylesheets.api import StylesheetManager

# Register widgets with their stylesheet PathDefs
manager = StylesheetManager.instance()
manager.register(my_widget, [MyModule.Paths.Stylesheet])

# Never hardcode QSS in Python code. Use .setObjectName() and external .qss files
my_widget.setObjectName("mySpecificWidget")

3. Paths - PathDef System

from src.shared_services.constants.paths import Logging, Icons
from src.shared_services.path_management.api import get_path, get_path_str

# pathlib.Path for filesystem operations
log_dir = get_path(Logging.Directory)

# String for Qt APIs
icon_str = get_path_str(Icons.Logos.GitHub)

4. File Operations - Atomic I/O

from src.shared_services.file_operations.api import save_json, load_json

# Always use these instead of raw open()/json.load()
data = load_json(MyPaths.ConfigFile)
save_json(MyPaths.ConfigFile, data)

5. Prompt Dialogs

from src.shared_services.prompt_dialogs.api import show_info, show_warning, show_error, ask_question

show_info("Erfolgreich gespeichert.", "Info", parent_widget)
show_warning("Ungespeicherte Aenderungen!", "Warnung", parent_widget)
result = ask_question("Moechten Sie fortfahren?", "Bestaetigung", parent_widget)

6. Application State

from src.shared_services.state.app_state import AppState

state = AppState.instance()
is_active = state.is_software_active
state.set_active_software("Plant Design")

7. Logging

# Always import locally, never at module level
def my_method(self) -> None:
    from src.shared_services.logging.logger_factory import get_logger
    logger = get_logger()
    logger.info("Operation completed")

Code Quality Requirements

1. Type Hints - MANDATORY

All function signatures MUST have type hints:

def calculate_total(self, quantity: int, discount: float = 0.0) -> float:
    """Calculate total with optional discount."""
    return quantity * self._unit_price * (1 - discount)

2. Docstrings - Google Style

All public classes, methods, and functions MUST have docstrings:

def add_item(self, item: str) -> None:
    """Add an item to the collection.

    Args:
        item: The item to add. Must not be empty.

    Raises:
        ValueError: If item is empty or already exists.
    """

3. PySide6 Signal/Slot Requirements

class MyController(QObject):
    """Controller with proper signal/slot patterns."""

    # Signal type annotations
    data_changed: Signal = Signal(list)
    error_occurred: Signal = Signal(str)

    @Slot()
    def on_button_clicked(self) -> None:
        """Handle button click."""
        self._process_data()

    @Slot(str)
    def on_data_received(self, data: str) -> None:
        """Handle received data."""
        self._update_model(data)

4. Error Handling

Use specific exceptions, never bare except:

try:
    result = operation()
except ValueError as e:
    from src.shared_services.logging.logger_factory import get_logger
    get_logger().error(f"Validation failed: {e}")
except FileNotFoundError as e:
    from src.shared_services.prompt_dialogs.api import show_error
    show_error(f"Datei nicht gefunden: {e}", "Fehler", self)

5. Background Workers

Use QRunnable with a nested Signals class:

from PySide6.QtCore import QObject, QRunnable, QThreadPool, Signal

class MyWorker(QRunnable):
    """Background worker for heavy operations."""

    class Signals(QObject):
        finished: Signal = Signal()
        error: Signal = Signal(str)
        result: Signal = Signal(object)

    def __init__(self) -> None:
        super().__init__()
        self.signals = self.Signals()

    def run(self) -> None:
        try:
            result = self._do_work()
            self.signals.result.emit(result)
        except Exception as e:
            self.signals.error.emit(str(e))
        finally:
            self.signals.finished.emit()

# Usage
worker = MyWorker()
worker.signals.result.connect(self._on_result)
QThreadPool.globalInstance().start(worker)

Anti-Patterns to AVOID

1. Hardcoded Stylesheets

# WRONG
button.setStyleSheet("background-color: #2196F3; color: white;")

# CORRECT
button.setObjectName("primaryButton")
# Styling handled in external .qss file via StylesheetManager

2. Global Logger

# WRONG
from src.shared_services.logging.logger_factory import get_logger
logger = get_logger()

# CORRECT - import locally
def my_method(self) -> None:
    from src.shared_services.logging.logger_factory import get_logger
    logger = get_logger()

3. Raw File I/O for App Data

# WRONG
with open("data/config.json", "r") as f:
    config = json.load(f)

# CORRECT
from src.shared_services.file_operations.api import load_json
config = load_json(MyPaths.ConfigFile)

4. Unicode Symbols

# WRONG
status_text = "Status: \u2714 Erfolgreich"

# CORRECT
status_text = "Status: [OK] Erfolgreich"

5. Code in init.py

# WRONG - __init__.py with imports
from .my_module import MyClass
__all__ = ["MyClass"]

# CORRECT - empty __init__.py
# (leave the file completely empty)

6. Non-Theme-Aware Icons

# WRONG - Does not update on theme change
from src.shared_services.rendering.icons.api import render_svg
button.setIcon(render_svg(Icons.Action.Save, size=24))

# CORRECT - Theme-aware
registry = IconRegistry.instance()
registry.register(button, Icons.Action.Save, color=IconColors.Primary)

Code Review Checklist

Before submitting code, verify:

General

  • [ ] All functions have type hints
  • [ ] All public APIs have Google-style docstrings
  • [ ] No bare except clauses
  • [ ] Comments in English, user-facing text in German (with direct umlauts)
  • [ ] No Unicode symbols anywhere

Project Systems

  • [ ] Icons use IconRegistry.register() (not raw render_svg for widgets)
  • [ ] No hardcoded QSS - use .setObjectName() + external stylesheets
  • [ ] Paths use PathDef constants with get_path()/get_path_str()
  • [ ] File I/O uses file_operations.api (not raw open/json)
  • [ ] Dialogs use prompt_dialogs.api functions
  • [ ] Logger imported locally, never globally
  • [ ] __init__.py files are empty

PySide6

  • [ ] Signals have type annotations (Signal = Signal(type))
  • [ ] Slots use @Slot decorator
  • [ ] Connection types specified when not AutoConnection
  • [ ] Memory cleanup implemented (deleteLater, parent-child)
  • [ ] No GUI access from worker threads

Version: 2.1 Last Updated: 2026-03-19 Maintainer: Max (Project Owner)