# How the claude-video Config Module Loads .env Settings and Strips Inline Comments

> Discover how the claude-video config module loads .env settings, efficiently stripping inline comments from unquoted values for seamless environment configuration.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-07-14

---

**The config module in claude-video loads environment variables from `~/.config/watch/.env` using a custom UTF-8 parser that strips inline comments from unquoted values while preserving them inside quoted strings, then resolves final settings with environment variables taking precedence over file defaults.**

The [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py) module in the bradautomates/claude-video repository centralizes configuration management for the **watch** skill. It implements a deterministic, dependency-free configuration loader that handles file parsing, inline comment removal, and multi-layer precedence resolution.

## Locating the Configuration File

According to the source code, the module defines the user-specific configuration directory at lines 9-10:

```python
CONFIG_DIR = Path.home() / ".config" / "watch"
ENV_FILE = CONFIG_DIR / ".env"

```

The parser expects the environment file to exist at `~/.config/watch/.env`. This path is exposed in the configuration dictionary returned by `get_config()`, allowing other modules to reference the absolute location of active settings.

## Parsing .env Files with read_env_file()

The `read_env_file()` function (lines 17-45) implements a manual parser to avoid external dependencies. It performs the following operations:

1. Reads the entire file as UTF-8 text and splits it into lines
2. Ignores empty lines, comment-only lines beginning with `#`, and lines lacking an `=` delimiter
3. Splits each valid line at the first `=` into key-value pairs
4. Strips surrounding whitespace from both keys and values

### Handling Quoted Values

For values wrapped in single or double quotes, the parser strips the surrounding quotes while preserving the inner content exactly. This ensures that API keys or strings containing special characters remain intact.

### Stripping Inline Comments from Unquoted Values

Lines 36-44 contain the critical logic for **inline comment stripping**. When processing unquoted values, the parser searches for a `#` character that is preceded by whitespace. Upon finding this pattern, it truncates the value at that position:

```python

# Logic from lines 36-44: Check for inline comments in unquoted values

if " #" in value:
    value = value.split(" #")[0].strip()

```

This approach allows unquoted values like `WATCH_DETAIL=balanced  # default mode` to resolve to `balanced`, while still permitting `#` characters inside quoted strings such as `WHISPER_API_KEY="sk-abc123#def"`.

## Configuration Resolution Precedence

The `get_config()` function (lines 48-62) implements a three-tier precedence system for the **`WATCH_DETAIL`** setting:

1. **Environment variable** (`os.environ.get("WATCH_DETAIL")`)
2. **File value** from `read_env_file()`
3. **Fallback constant** `DEFAULT_DETAIL` (`"balanced"`)

After resolution, the function validates the detail level against the allowed `DETAILS` set (defined on lines 14-15). If the resolved value is invalid, it defaults to `"balanced"`. The function returns a dictionary containing the effective `detail` string and the absolute `config_file` path.

## Frame Rate Cap Utilities

The `frame_cap(detail)` function (lines 65-74) maps validated detail levels to numeric frame-rate caps:

- `efficient` → `10` FPS
- `balanced` → `100` FPS  
- `quality` → `None` (unlimited)

This utility allows the watch skill to enforce performance limits based on user configuration without hardcoding logic throughout the codebase.

## Practical Implementation Examples

### Loading Configuration with Inline Comments

Create a `.env` file at `~/.config/watch/.env`:

```dotenv

# Choose the level of detail for frame extraction

WATCH_DETAIL=balanced  # default balanced mode

# Optional API key – keep it quoted to preserve the #

WHISPER_API_KEY="sk-abc123#def"

```

Access the configuration in Python:

```python
from skills.watch.scripts.config import get_config

cfg = get_config()
print(cfg)

# Output: {'detail': 'balanced', 'config_file': '/home/username/.config/watch/.env'}

```

### Environment Variable Override

Environment variables take precedence over file settings:

```bash
export WATCH_DETAIL=efficient
python -c "from skills.watch.scripts.config import get_config; print(get_config())"

# Output: {'detail': 'efficient', 'config_file': '/home/username/.config/watch/.env'}

```

### Applying Frame Rate Caps

Determine the maximum frames per second based on the current detail setting:

```python
from skills.watch.scripts.config import frame_cap, get_config

detail = get_config()["detail"]
max_fps = frame_cap(detail)
print(f"Detail mode: {detail}, max FPS: {max_fps if max_fps else 'unlimited'}")

# For `balanced` → max FPS: 100

```

## Summary

- The config module reads settings from `~/.config/watch/.env` using a custom parser implemented in [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py).
- **Inline comments** are stripped from unquoted values when a `#` is preceded by whitespace, but preserved inside quoted strings.
- Configuration resolution follows strict precedence: environment variables override file values, which override the `DEFAULT_DETAIL` constant (`"balanced"`).
- Valid detail levels are validated against the `DETAILS` set, with automatic fallback to the default if an invalid value is encountered.
- The `frame_cap()` utility maps detail levels to numeric FPS limits or `None` for unlimited processing.

## Frequently Asked Questions

### Where does claude-video store its configuration file?

The config module stores settings in `~/.config/watch/.env` (lines 9-10 of [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py)). This path is constructed using `Path.home()` to ensure cross-platform compatibility, creating a user-specific configuration directory that persists across sessions.

### How does the config module handle API keys containing hash symbols?

The parser preserves `#` characters inside quoted values (single or double quotes) but strips them from unquoted values when preceded by whitespace. To store an API key like `sk-abc123#def`, wrap it in quotes: `WHISPER_API_KEY="sk-abc123#def"`. This prevents the inline comment stripper (lines 36-44) from truncating the value at the hash symbol.

### What takes precedence: environment variables or the .env file?

Environment variables take highest precedence. The `get_config()` function checks `os.environ` first, then falls back to values from `read_env_file()`, and finally uses `DEFAULT_DETAIL` if neither source provides a valid setting. This allows temporary overrides without modifying the configuration file.

### What detail levels are supported and what are their frame caps?

The supported detail levels are defined in the `DETAILS` set (lines 14-15): `efficient`, `balanced`, and `quality`. According to the `frame_cap()` implementation (lines 65-74), `efficient` caps at 10 FPS, `balanced` caps at 100 FPS, and `quality` returns `None` for unlimited frame processing.