Skip to main content

ADR-121: Path Discovery Consolidation

Status

ACCEPTED (2026-01-27)

Context

Problem Statement

Following ADR-120 (Customer Extensions Architecture), which established ~/.coditect-data/ as the single location for all customer data and extensions, we discovered that 135+ files across the codebase have inconsistent path handling:

Issue TypeCountDescription
Wrong import70+from paths import instead of from scripts.core.paths import
Hardcoded paths50+Path.home() / "PROJECTS" / ".coditect-data" inline
Inconsistent fallbacks30+Mixed patterns for handling import failures
MCP servers3Hardcoded paths, no centralized module usage

Why This Matters

  1. ADR-114 Compliance: The path discovery module (scripts/core/paths.py) implements configurable PROJECTS location, but most files bypass it
  2. Customer Portability: Customers with non-standard PROJECTS locations will have broken tools
  3. Maintenance Burden: Path changes require updating 135+ files instead of one
  4. Extensions Support: ADR-120 added extensions/ directory which no existing code knows about

Discovery Process

MoE analysis using codebase exploration agents identified:

hooks/              24 files with issues
hooks/validators/ 8 files with issues
scripts/ 100+ files with issues
scripts/core/ 15 files with issues
tools/mcp-*/ 3 files with issues
─────────────────────────────────────────
Total ~135 files need updating

Decision

1. Create Standardized Import Helper

Create scripts/core/paths_helper.py that:

  • Automatically discovers and adds coditect-core to sys.path
  • Re-exports all paths.py constants and functions
  • Provides graceful fallbacks for bootstrapping scenarios
  • Adds EXTENSIONS_DIR constant (ADR-120)

2. Establish Standard Import Pattern

All hooks and scripts MUST use this pattern:

# Path discovery (ADR-114, ADR-120)
import sys
from pathlib import Path
_script_dir = Path(__file__).resolve().parent.parent
if str(_script_dir) not in sys.path:
sys.path.insert(0, str(_script_dir))

try:
from scripts.core.paths import (
USER_DATA_LOC, CONTEXT_STORAGE, SESSION_LOGS, EXTENSIONS_DIR,
get_user_data_dir, get_context_storage_dir, get_session_logs_dir
)
PATHS_AVAILABLE = True
except ImportError:
PATHS_AVAILABLE = False
USER_DATA_LOC = Path.home() / "PROJECTS" / ".coditect-data"
CONTEXT_STORAGE = USER_DATA_LOC / "context-storage"
SESSION_LOGS = USER_DATA_LOC / "session-logs"
EXTENSIONS_DIR = USER_DATA_LOC / "extensions"

3. Add Extensions Directory to paths.py

Added get_extensions_dir() function and EXTENSIONS_DIR constant:

def get_extensions_dir() -> Path:
"""Get the customer extensions directory (ADR-120)."""
return get_user_data_dir() / "extensions"

EXTENSIONS_DIR = get_extensions_dir()

4. Update All Affected Files

Batch update all 135+ files to use the standardized import pattern.

Implementation

Phase 1: Infrastructure (Complete)

FileStatusPurpose
scripts/core/paths_helper.pyCreatedStandardized import helper
scripts/core/paths.pyUpdatedAdded get_extensions_dir(), EXTENSIONS_DIR

Phase 2: Hooks (24 files)

Files in hooks/:

  • dispatcher.py, pre-backup.py, post-backup.py, pre-restore.py, post-restore.py
  • session-retrospective.py, session-retrospective-v2.py
  • auto-session-namer.py, proactive-error-suggester.py
  • session-start-context.py, session-auto-recall.py
  • task-tracking-enforcer.py, task-plan-sync.py
  • antipattern-detector.py, classify_document.py
  • component-database-sync.py, hook_logger.py
  • migration-safety-validator.py, scheduled-backup-monitor.py
  • skill-preflight-validator.py, token-limit-pivot-detector.py
  • context-threshold-monitor.py, export-centralizer.py
  • post-meeting-analysis-hook.py

Phase 3: Validators (8 files)

Files in hooks/validators/:

  • backup-integrity-validator.py
  • context-extraction-validator.py
  • context-query-validator.py
  • orient-context-validator.py
  • install-script-validator.py
  • project-plan-update-validator.py
  • task-id-protocol-validator.py
  • deprecation-audit-validator.py

Phase 4: Core Scripts (15 files)

Files in scripts/core/:

  • activation_test_suite.py, capability_discovery.py, cloud_sync_client.py
  • component_metadata_registry.py, db_backup.py, db_init.py, db_migrate.py, db_seed.py
  • ensure_component_registered.py, intent_context_manager.py
  • license_validator.py, license-activate.py
  • memory_context_integration.py, nested_learning.py, trajectory_logging.py

Phase 5: Main Scripts (85+ files)

Files in scripts/ using from paths import:

  • work_items.py, query-work-items.py, migrate-tasks-to-v2.py
  • trajectory_extractor.py, backup-status.py, generate-session-insights.py
  • task-extraction-pipeline.py, migrate-ralph-wiggum-schema.py
  • import-tasks-from-markdown.py, task-dispatcher.py, sync-project-plan.py
  • memory-retrieval.py, learning-db-migrate.py, autonomous-orchestrator.py
  • agent-executor.py, sync-daemon.py, skill-selector.py
  • learning_db_query.py, component-discover.py, skill-mentor.py
  • deduplicate-all-tables.py, audit_trail.py, context_snapshot.py
  • component-indexer.py, reset-skill-learnings-baseline.py
  • ... (70+ more)

Phase 6: MCP Servers (3 files)

Files in tools/:

  • tools/mcp-impact-analysis/server.py
  • tools/mcp-semantic-search/server.py
  • tools/mcp-call-graph/server.py

Consequences

Positive

  1. Single Source of Truth: All path discovery goes through paths.py
  2. Customer Portability: $CODITECT_PROJECTS env var works everywhere
  3. ADR-120 Ready: Extensions directory available in all scripts
  4. Maintainability: Future path changes need only one file update
  5. Graceful Degradation: Fallback pattern handles bootstrapping

Negative

  1. Large Refactor: 135+ files need updating
  2. Risk of Regressions: Any file missed could break
  3. Import Overhead: Additional sys.path manipulation

Mitigation

  1. Batch Updates: Process files by category
  2. Verification Script: Run after each batch to verify imports work
  3. Fallbacks Preserved: Hardcoded fallbacks still work if import fails

Verification

# Test paths.py directly
python3 scripts/core/paths.py

# Test paths_helper.py
python3 scripts/core/paths_helper.py

# Test import from hook location
cd hooks && python3 -c "from scripts.core.paths import USER_DATA_LOC; print(USER_DATA_LOC)"

# Verify specific hook
python3 hooks/dispatcher.py --help
ADRTitleRelationship
ADR-114User Data SeparationParent - defines paths.py
ADR-120Customer ExtensionsAdds extensions/ directory
ADR-118Four-Tier DatabaseDatabase paths in paths.py
ADR-057Initial SetupCreates symlinks and paths

Path Discovery Priority (ADR-114)

1. Environment variable: $CODITECT_PROJECTS
2. Config file: ~/.coditect/config/config.json → projects_dir
3. Symlink discovery: Find .coditect symlink parent
4. Default fallback: ~/PROJECTS

Final Structure

~/PROJECTS/.coditect-data/           # USER_DATA_LOC
├── machine-id.json # MACHINE_ID_FILE
├── checkpoints/
├── backups/ # BACKUPS_DIR
├── context-storage/ # CONTEXT_STORAGE
│ ├── org.db # ORG_DB
│ ├── sessions.db # SESSIONS_DB
│ ├── platform.db
│ └── unified_messages.jsonl
├── session-logs/ # SESSION_LOGS
│ └── SESSION-LOG-*.md
└── extensions/ # EXTENSIONS_DIR (NEW)
├── agents/
├── skills/
├── hooks/
├── commands/
├── scripts/
├── tools/
└── config/

Changelog

DateAuthorChange
2026-01-27Claude Opus 4.5Initial creation
2026-01-27MoE Analysis135 files identified for update