Skip to main content

ADR-155: Project-Scoped Session Logs Architecture

Status

ACCEPTED (2026-02-03)

Context

Problem Statement

CODITECT's current session logging architecture (ADR-058) organizes session logs by machine, with logs stored at ~/PROJECTS/.coditect-data/session-logs/{machine-uuid}/. While this approach enables machine-specific session tracking, it creates several problems when working across multiple projects:

  1. No project isolation - Session logs from all projects on a machine are intermingled in the same directory. When working on a customer project (e.g., Avivatec FP&A), session data is mixed with internal CODITECT framework work.

  2. Session attribution confusion - The /session-log command writes to the daily log for the machine, regardless of which project is active. Entries from different projects appear in the same log file with no clear separation.

  3. Customer data leakage risk - Customer project session logs (potentially containing sensitive financial data, business logic, or proprietary information) are stored alongside internal project logs. This complicates data governance and compliance (LGPD, SOC 2).

  4. Multi-LLM session mixing - When using /sx to export sessions from multiple LLMs, all exports go to the same pending directories regardless of project context.

  5. Context query pollution - The /cxq command searches all session data, returning results from unrelated projects and reducing signal-to-noise ratio.

Current State

ComponentCurrent BehaviorLimitation
Session logs~/.coditect-data/session-logs/{machine-uuid}/Machine-scoped, not project-scoped
/session-logWrites to daily log for machineNo project isolation
/sx exportsPending directories per LLMNo project filtering
/cx extractionProcesses all pending sessionsNo project attribution
/cxq queriesSearches all messagesNo project filtering

Requirements

  1. Session logs organized by project, enabling clear separation between projects
  2. Backward compatibility with existing machine-specific logs
  3. Support for customer project isolation (tenant-scoped session logs)
  4. Integration with Project Registry (ADR-144) for project discovery
  5. Migration path for existing session logs without data loss
  6. Multi-LLM export support with project attribution

Decision

1. Hierarchical Session Log Directory Structure

Extend the session log directory structure to support project scoping while maintaining backward compatibility:

~/PROJECTS/.coditect-data/
├── session-logs/
│ ├── {machine-uuid}/ # Legacy machine-scoped (backward compat)
│ │ └── YYYY-MM-DD.md # Daily logs
│ │
│ └── projects/ # NEW: Project-scoped logs
│ ├── PILOT/ # Platform project
│ │ ├── {machine-uuid}/
│ │ │ └── YYYY-MM-DD.md
│ │ └── exports/ # Project-specific exports
│ │
│ ├── CUST-avivatec-fpa/ # Customer project
│ │ ├── {machine-uuid}/
│ │ │ └── YYYY-MM-DD.md
│ │ └── exports/
│ │
│ └── PROJ-experiment/ # Personal project
│ ├── {machine-uuid}/
│ └── exports/

├── sessions-export-pending-anthropic/ # Legacy (backward compat)
├── sessions-export-pending-codex/
├── sessions-export-pending-gemini/
├── sessions-export-pending-kimi/

└── sessions-export-pending/ # NEW: Project-scoped exports
├── PILOT/
│ ├── anthropic/
│ ├── codex/
│ ├── gemini/
│ └── kimi/
└── CUST-avivatec-fpa/
├── anthropic/
└── ...

2. Session Log Scoping Rules

Project ScopeLog LocationExport Location
platformprojects/PILOT/{machine}/sessions-export-pending/PILOT/
orgprojects/{project_id}/{machine}/sessions-export-pending/{project_id}/
customerprojects/CUST-{tenant}-{slug}/{machine}/sessions-export-pending/CUST-{tenant}-{slug}/
projectprojects/PROJ-{slug}/{machine}/sessions-export-pending/PROJ-{slug}/
Unscoped (legacy){machine-uuid}/sessions-export-pending-{llm}/

3. Command Updates

/session-log Enhancement

# Current behavior (no project context)
/session-log "Work completed"
# Writes to: session-logs/{machine-uuid}/YYYY-MM-DD.md

# NEW: With project context
/session-log "FPA.A.1.1 completed"
# Detects project from $CODITECT_PROJECT or cwd
# Writes to: session-logs/projects/CUST-avivatec-fpa/{machine}/YYYY-MM-DD.md

# Explicit project override
/session-log --project PILOT "Framework work done"
# Writes to: session-logs/projects/PILOT/{machine}/YYYY-MM-DD.md

Implementation in /session-log command:

def get_session_log_path(project_id: Optional[str] = None) -> Path:
"""Get the session log path, scoped to project if available."""
from scripts.core.paths import get_user_data_dir, get_machine_uuid

data_dir = get_user_data_dir()
machine_uuid = get_machine_uuid()
today = datetime.now().strftime('%Y-%m-%d')

# Determine project context
if project_id is None:
project_id = os.environ.get('CODITECT_PROJECT')

if project_id:
# Project-scoped path
log_dir = data_dir / 'session-logs' / 'projects' / project_id / machine_uuid
else:
# Legacy machine-scoped path
log_dir = data_dir / 'session-logs' / machine_uuid

log_dir.mkdir(parents=True, exist_ok=True)
return log_dir / f'{today}.md'

/sx Enhancement

# NEW: Project-scoped export
/sx --project CUST-avivatec-fpa
# Exports to: sessions-export-pending/CUST-avivatec-fpa/{llm}/

# Auto-detect from context
/sx
# If $CODITECT_PROJECT=CUST-avivatec-fpa, uses project-scoped directory
# Otherwise, falls back to legacy directories

/cxq Enhancement

# NEW: Project-filtered query
/cxq --project PILOT "deployment"
# Searches only PILOT session data

# Multi-project query
/cxq --project PILOT,CUST-avivatec-fpa "architecture"

# Exclude project
/cxq --exclude-project CUST-avivatec-fpa "all sessions"

4. Database Schema Updates

Extend sessions.db (Tier 3) to support project attribution:

-- ============================================================
-- ALTER: messages table - add project_id column
-- ============================================================
ALTER TABLE messages ADD COLUMN project_id TEXT;

-- Index for project-scoped queries
CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id);

-- ============================================================
-- View: project_messages
-- Purpose: Filter messages by project
-- ============================================================
CREATE VIEW IF NOT EXISTS project_messages AS
SELECT
m.*,
p.name AS project_name,
p.scope AS project_scope
FROM messages m
LEFT JOIN projects p ON m.project_id = p.project_id
WHERE m.project_id IS NOT NULL;

5. Project Detection Flow

┌─────────────────────────────────────────────────────────────────┐
│ /session-log invocation │
│ │ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ --project flag provided? │ │
│ └──────────────────────────────┘ │
│ │ │ │
│ YES NO │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Use provided │ │ Check $CODITECT_PROJECT │ │
│ │ project_id │ │ env var │ │
│ └─────────────────┘ └──────────────────────────┘ │
│ │ │ │ │
│ │ SET NOT SET │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌─────────────┐ ┌──────────────────┐ │
│ │ │ Use env var │ │ Run discover_ │ │
│ │ │ project_id │ │ project(cwd) │ │
│ │ └─────────────┘ └──────────────────┘ │
│ │ │ │ │
│ │ │ FOUND / NOT FOUND │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────────────────────────────┐ ┌──────┐ │
│ │ Write to project-scoped path │ │Legacy│ │
│ │ projects/{project_id}/{machine}/ │ │ path │ │
│ └────────────────────────────────────┘ └──────┘ │
└─────────────────────────────────────────────────────────────────┘

6. Migration Strategy

Phase 1: Schema Addition (Non-Breaking)

  1. Add project_id column to messages table in sessions.db
  2. Create project-scoped directory structure
  3. Update /session-log to detect project context (opt-in)

Phase 2: Backfill Existing Data

def migrate_session_logs_to_project(project_id: str, date_range: tuple):
"""
Migrate existing machine-scoped session logs to project-scoped location.
Uses heuristics to attribute logs to projects based on:
- Task IDs (e.g., FPA.A.1.1 → CUST-avivatec-fpa)
- Directory paths mentioned in logs
- Session metadata
"""
pass

Phase 3: Command Updates

  1. /session-log - Auto-detect project, write to scoped path
  2. /sx - Support --project flag, auto-detect from context
  3. /cx - Attribute extracted messages to projects
  4. /cxq - Support --project filtering

Phase 4: Deprecation

  1. Add warning when writing to legacy machine-scoped path
  2. Recommend migration to project-scoped structure
  3. After 8 weeks, make project scoping the default

7. Customer Data Isolation

For customer scope projects, additional isolation requirements apply:

RequirementImplementation
Data residencySession logs stored in project-specific directory
Access controlDirectory permissions restrict to project owner
Backup isolationPer-project backup to separate GCS buckets
Audit trailAll access logged to project-specific audit log
Data deletion/project delete removes all project session data
def ensure_customer_data_isolation(project_id: str, tenant_id: str):
"""Ensure customer project data is properly isolated."""
project_dir = get_project_session_dir(project_id)

# Set restrictive permissions
os.chmod(project_dir, 0o700)

# Create .tenant file for audit
(project_dir / '.tenant').write_text(tenant_id)

# Initialize project-specific backup config
backup_config = {
'bucket': f'gs://coditect-customer-{tenant_id}-backups',
'encryption': 'customer-managed',
'retention_days': 365
}
(project_dir / '.backup-config.json').write_text(json.dumps(backup_config))

Consequences

Positive

  1. Clear project isolation - Session logs from different projects are physically separated
  2. Customer data protection - Customer project data is isolated for compliance (LGPD, SOC 2)
  3. Focused context queries - /cxq --project returns only relevant results
  4. Multi-project support - Seamless switching between projects with proper log attribution
  5. Backward compatibility - Existing machine-scoped logs continue to work
  6. Audit trail - Clear lineage of which sessions belong to which project

Negative

  1. Directory complexity - More nested directory structure to manage
  2. Migration effort - Existing logs need attribution/migration
  3. Storage overhead - Duplicate structure for project-scoped vs legacy paths
  4. Discovery overhead - Project detection adds latency to log writes

Risks and Mitigations

RiskLikelihoodMitigation
Logs written to wrong projectMediumValidate project_id against registry; warn on mismatch
Orphaned project directoriesLowPeriodic cleanup of directories for deleted projects
Performance impact from project detectionLowCache project context in environment; lazy detection
Migration data lossLowMigration is additive; original logs preserved

Implementation Plan

Week 1: Foundation

  • Create project-scoped directory structure
  • Add project_id column to sessions.db messages table
  • Implement get_session_log_path() with project support
  • Update /session-log command to use project context

Week 2: Export Integration

  • Update /sx to support --project flag
  • Create project-scoped export directories
  • Update /cx to attribute messages to projects
  • Add --project filter to /cxq

Week 3: Migration

  • Implement session log migration script
  • Backfill project_id for existing messages
  • Add deprecation warnings for legacy paths
  • Document migration process

Week 4: Validation

  • Test customer data isolation
  • Verify backward compatibility
  • Performance testing for project detection
  • Update documentation

Implementation Status (J.27)

Track: J.27 (Project-Scoped Session Log Sync) | Updated: 2026-02-08

PhaseSubtaskStatusImplementation
FoundationJ.27.1 SSOT Location✅ Completeprojects/{project_id}/{machine}/ with symlinks
FoundationJ.27.2 Sync Script✅ Completesession-log-git-sync.py v4.0.0
IsolationJ.27.3 Multi-Tenant✅ Complete0o700 permissions, --tenant, PII scanning
MigrationJ.27.4 Legacy Attribution✅ Completemigrate-legacy-session-logs.py, deprecation warnings
ValidationJ.27.5 Testing✅ Complete50 unit tests in test_session_log_git_sync.py
DocsJ.27.6 Documentation✅ Complete/sync-logs v2.0.0, CLAUDE.md, ADR diagram

Sync Architecture Diagram

~/.coditect-data/session-logs/              SESSION-LOG-GIT-SYNC.PY v4.0.0
├── projects/ ┌────────────────────────────┐
│ ├── PILOT/{uuid}/ │ discover_all_logs() │
│ │ ├── SESSION-LOG-2026-01-01.md ─────►│ ├── --project PILOT │
│ │ └── SESSION-LOG-2026-02-08.md ─────►│ ├── --tenant avivatec │
│ └── CUST-avivatec-fpa/{uuid}/ (0o700) │ └── PII scan (CUST-*) │
│ └── SESSION-LOG-2026-01-15.md ─────►│ │
│ │ sync_logs() │
│ (legacy flat symlinks → projects/PILOT/) │ ├── copy to git repo │
│ │ ├── enforce permissions │
└── SESSION-LOG-*.md ──(symlink)──► │ └── git commit + push │
└─────────────┬──────────────┘

~/.coditect-data/session-logs-git/
└── machines/{uuid}/
└── projects/
├── PILOT/SESSION-LOG-*.md
└── CUST-avivatec-fpa/SESSION-LOG-*.md

git push (ADR-159 routing)

github.com/coditect-ai/
coditect-core-sessions-logs (private)
ADRRelationship
ADR-058Extended by this ADR for project scoping
ADR-186User data location where session logs reside
ADR-118sessions.db schema extended with project_id
ADR-144Project registry used for project discovery
ADR-159Multi-tenant routing for per-project git repos