## Development Philosophy

**Clean code over backward compatibility.** Breaking changes are acceptable in major versions.

- PEP8 compliance (snake_case for all variables/functions/settings)
- Remove deprecated code completely - no compatibility hacks
- Trust users to update configs when upgrading

**Exception**: Never break core accessibility (speech output, basic navigation).

## Core Architecture

### Drivers
- **Screen**: `vcsaDriver` (TTY), `ptyDriver` (terminal emulation)
- **Input**: `evdevDriver` (evdev), `x11Driver` (X11 terminal mode)
- **Speech**: `speechdDriver` (speech-dispatcher), `genericDriver` (subprocess)
- **Sound**: `gstreamerDriver` (GStreamer), `genericDriver` (Sox subprocess)
- **Remote**: `unixDriver` (Unix sockets), `tcpDriver`

### Command System
Commands in trigger folders execute automatically:
- `onKeyInput/`, `onCursorChange/`, `onScreenUpdate/`, `onScreenChanged/`, `onHeartBeat/`
- Numeric prefixes control priority (lower = higher priority): `15000-char_echo.py`
- Manual commands in `commands/commands/`

### Core Managers (in `src/fenrirscreenreader/core/`)
`fenrirManager.py`, `commandManager.py`, `eventManager.py`, `screenManager.py`, `inputManager.py`, `outputManager.py`

### Configuration
- Main: `config/settings/settings.conf`
- Keyboards: `config/keyboard/` (desktop.conf, laptop.conf)
- Sounds: `config/sound/`
- Punctuation: `config/punctuation/`

## 🚨 CRITICAL: Files to NEVER Modify

**These are timing-critical - only fix critical bugs, never refactor:**
- `evdevDriver.py` - Input event processing
- `vcsaDriver.py` - Screen monitoring

Symptoms of breakage: echo changes, input lag, missing screen updates, sync issues.

## Development Commands

```bash
# Run from source (requires root)
cd src/ && sudo ./fenrir -f -d   # foreground with debug

# Validation before commit
python3 tools/validate_syntax.py --fix
python3 tools/validate_release.py --quick

# Tests
pytest tests/
pytest tests/ --cov=src/fenrirscreenreader --cov-report=html
```

**Note**: Standard TTY Fenrir blocks - only one instance at a time. `fenrir -x`
can run multiple foreground X terminal instances. Ask user to run tests that
need real Fenrir instances or root access.

## Creating Commands

Use `commands/command_template.py` as base. Required methods:
- `initialize(self, environment)`, `shutdown()`, `run()`, `get_description()`

### Import Pattern (Required)
Fenrir's command loader doesn't support relative imports:
```python
import os, importlib.util
_base_path = os.path.join(os.path.dirname(__file__), 'base_file.py')
_spec = importlib.util.spec_from_file_location("base_module", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
BaseClass = _module.BaseClass
```

### Consolidated Base Classes
- **Bookmarks**: `bookmark_base.py` - `BookmarkCommand(id, 'read'|'set'|'clear')`
- **Adjustments**: `adjustment_base.py` - `AdjustmentCommand('speech'|'sound', 'rate'|'pitch'|'volume', 'inc'|'dec')`
- **VMenu Search**: `vmenu_search_base.py` - `VMenuSearchCommand('a'-'z')`

## VMenu System

Application-specific menus in `vmenu-profiles/KEY/{app}/`:
- Directories = submenus, `.py` files = actions
- Activate: `Fenrir+F10`, navigate with arrows, Enter to execute

## Remote Control

Unix socket: `/tmp/fenrirscreenreader-daemon.sock`
TCP: localhost:22447

```bash
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#rate=0.8" | nc localhost 22447
```

In `fenrir -x`, each instance has a private socket:
`/tmp/fenrirscreenreader-<pid>.sock`. One instance may also own the standard
socket. Use `ls`/`list` on the standard socket to discover registered instances
and their socket paths. Untargeted remote commands use a short cross-process
claim lock so only one instance handles the same broadcast command; direct
commands to a private instance socket still run on that instance.

Disable in untrusted environments: `[remote] enable=False`

## Key Implementation Details

- Commands via `command_mod.command()` instantiation
- Bookmark structure: `env['commandBuffer']['bookMarks'][ID][app]['1'/'2']`
- VMenu search: `env['runtime']['vmenuManager'].searchEntry(char)`

## Recent Fixes (Reference)

- Enhanced application detection for screen/tmux sessions
- Table navigation consistency (sound feedback)
- Blank line detection in 22 command files
- Character/space review during navigation

## Safe vs Risky Changes

**Safe**: Commands, VMenu profiles, config handling, sound/speech drivers, docs

**Risky (extra testing)**: Core managers, event processing

**Avoid**: evdevDriver, vcsaDriver, timing-critical code
