# Track Specification: Conductor Path Configuration (conductor_path_configurable_20260306)

## Overview
Eliminate all hardcoded paths in the application. Make directory paths configurable via `config.toml` or environment variables, allowing the running app to use different directories from development setup. This is **Phase 0 - Critical Infrastructure** that must be completed before other Phase 3 tracks.

## Current State Audit

### Already Implemented (DO NOT re-implement)

#### Environment Variable Pattern (models.py)
- **`CONFIG_PATH`**: `Path(os.environ.get("SLOP_CONFIG", "config.toml"))` - This pattern exists and should be replicated.

#### Hardcoded Path Inventory

| File | Line | Current Hardcode | Variable/Usage |
|------|------|------------------|----------------|
| `src/orchestrator_pm.py` | 10 | `"conductor"` | `CONDUCTOR_PATH: Path = Path("conductor")` |
| `src/project_manager.py` | 240 | `"conductor"` | `track_dir = Path(base_dir) / "conductor" / "tracks" / track_id` |
| `src/project_manager.py` | 252 | `"conductor"` | `state_file = Path(base_dir) / "conductor" / "tracks" / track_id / "state.toml"` |
| `src/project_manager.py` | 297 | `"conductor"` | `tracks_dir = Path(base_dir) / "conductor" / "tracks"` |
| `src/app_controller.py` | 1907 | `"conductor"` | `base = Path("conductor")` |
| `src/app_controller.py` | 1937 | `"conductor"` | `track_dir = Path("conductor/tracks") / track_id` |
| `src/app_controller.py` | 643 | `"logs/sessions"` | `initialdir="logs/sessions"` |
| `src/app_controller.py` | 674 | `"logs/sessions"` | `LogRegistry("logs/sessions/log_registry.toml")` |
| `src/app_controller.py` | 1241 | `"logs/sessions"` | `log_dir = Path("logs/sessions")` |
| `src/gui_2.py` | 776 | `"logs/sessions"` | `LogRegistry("logs/sessions/log_registry.toml")` |
| `src/session_logger.py` | 26 | `"./logs/sessions"` | `_LOG_DIR: Path = Path("./logs/sessions")` |
| `src/session_logger.py` | 27 | `"./scripts/generated"` | `_SCRIPTS_DIR: Path = Path("./scripts/generated")` |

#### Notes on Existing Implementation
- `session_logger.py` has module-level path constants that are set once at import time
- `project_manager.py` uses `base_dir` parameter but hardcodes `"conductor"` as subdirectory
- `app_controller.py` has multiple scattered hardcodes that need consolidation

### Gaps to Fill (This Track's Scope)
- No centralized path configuration module
- No `config.toml` section for paths
- No environment variable support for logs, scripts, or conductor directories
- Duplicate path definitions across files

## Architectural Constraints

### Single Source of Truth
- All paths MUST be resolved through a single `paths.py` module
- No file should hardcode directory strings directly

### Initialization Order
- Path resolution MUST happen before any module imports that use paths
- `session_logger.py` imports at module level - may need lazy initialization

### Backward Compatibility
- Default paths MUST remain unchanged (relative to project root)
- Existing `SLOP_CONFIG` env var pattern MUST be preserved
- All existing function signatures that take `base_dir` MUST continue to work

### Thread Safety
- Path resolution is read-only after initialization
- No locks needed once paths are resolved

## Architecture Reference

### Key Integration Points

| File | Lines | Purpose |
|------|-------|---------|
| `src/models.py` | 27-28 | `CONFIG_PATH` pattern to replicate |
| `src/orchestrator_pm.py` | 10 | `CONDUCTOR_PATH` to replace |
| `src/project_manager.py` | 238-297 | Track state paths to update |
| `src/session_logger.py` | 26-27 | `_LOG_DIR`, `_SCRIPTS_DIR` to update |
| `src/app_controller.py` | 643, 674, 1241, 1907, 1937 | Multiple hardcodes to fix |
| `src/gui_2.py` | 776 | LogRegistry path to update |
| `config.toml` | N/A | Add `[paths]` section |

### Proposed Module Structure

```python
# src/paths.py (NEW FILE)

from pathlib import Path
import os
from typing import Optional
import tomllib

_CONFIG_PATH: Path = Path(os.environ.get("SLOP_CONFIG", "config.toml"))
_RESOLVED: dict[str, Path] = {}

def _resolve_path(env_var: str, config_key: str, default: Path) -> Path:
 """Resolve path from env var, config, or default."""
 if env_var in os.environ:
  return Path(os.environ[env_var])
 if _CONFIG_PATH.exists():
  with open(_CONFIG_PATH, "rb") as f:
   cfg = tomllib.load(f)
   if "paths" in cfg and config_key in cfg["paths"]:
    return Path(cfg["paths"][config_key])
 return default

def get_conductor_dir() -> Path: ...
def get_logs_dir() -> Path: ...
def get_scripts_dir() -> Path: ...
def get_config_path() -> Path: ...
```

## Functional Requirements

### FR1: Config File Support
Add `[paths]` section to `config.toml`:
```toml
[paths]
conductor_dir = "conductor"
logs_dir = "logs/sessions"
scripts_dir = "scripts/generated"
# config_file uses SLOP_CONFIG env var (existing)
```

### FR2: Environment Variable Support
| Env Var | Config Key | Default |
|---------|------------|---------|
| `SLOP_CONDUCTOR_DIR` | `conductor_dir` | `"conductor"` |
| `SLOP_LOGS_DIR` | `logs_dir` | `"logs/sessions"` |
| `SLOP_SCRIPTS_DIR` | `scripts_dir` | `"scripts/generated"` |
| `SLOP_CONFIG` | (existing) | `"config.toml"` |

### FR3: Centralized Path Module
Create `src/paths.py` with:
- `get_conductor_dir() -> Path`
- `get_logs_dir() -> Path`
- `get_scripts_dir() -> Path`
- `get_config_path() -> Path`
- `get_tracks_dir() -> Path` (conductor/tracks)
- `get_track_state_dir(track_id: str) -> Path`

### FR4: Module Migration
Update all modules to import from `paths.py`:
- `orchestrator_pm.py`: Use `paths.get_conductor_dir()`
- `project_manager.py`: Use `paths.get_tracks_dir()`
- `session_logger.py`: Use `paths.get_logs_dir()`, `paths.get_scripts_dir()`
- `app_controller.py`: Use all path functions
- `gui_2.py`: Use `paths.get_logs_dir()`

## Non-Functional Requirements

| Requirement | Constraint |
|-------------|------------|
| Import Order | `paths.py` must be importable without side effects |
| Lazy Resolution | Path resolution on first access, not at import |
| No Breaking Changes | All existing code continues to work |
| Default Behavior | Unchanged when no config/env overrides |

## Testing Requirements

### Unit Tests
- Test each path function returns expected default
- Test env var override for each path
- Test config.toml override for each path
- Test env var takes precedence over config

### Integration Tests
- Verify app starts with custom paths
- Verify tracks load from custom conductor dir
- Verify logs write to custom logs dir

### Test Isolation
- Reset `_RESOLVED` dict between tests
- Mock `os.environ` for env var tests
- Use temp config files for config tests

## Out of Scope
- Runtime path changes (paths are resolved once at startup)
- Path validation (directory existence checks)
- Relative path resolution (always resolve to absolute)

## Acceptance Criteria
- [ ] `src/paths.py` module created with all path functions
- [ ] `config.toml` has `[paths]` section
- [ ] All 4 environment variables work
- [ ] Default paths remain unchanged
- [ ] `orchestrator_pm.py` uses `paths.get_conductor_dir()`
- [ ] `project_manager.py` uses path functions
- [ ] `session_logger.py` uses path functions
- [ ] `app_controller.py` uses path functions
- [ ] `gui_2.py` uses path functions
- [ ] All existing tests pass
- [ ] New path resolution tests pass
- [ ] 1-space indentation maintained
