Remove conversation context/recall system from ClaudeTools

Completely removed the database context recall system while preserving
database tables for safety. This major cleanup removes 80+ files and
16,831 lines of code.

What was removed:
- API layer: 4 routers (conversation-contexts, context-snippets,
  project-states, decision-logs) with 35+ endpoints
- Database models: 5 models (ConversationContext, ContextSnippet,
  DecisionLog, ProjectState, ContextTag)
- Services: 4 service layers with business logic
- Schemas: 4 Pydantic schema files
- Claude Code hooks: 13 hook files (user-prompt-submit, task-complete,
  sync-contexts, periodic saves)
- Scripts: 15+ scripts (import, migration, testing, tombstone checking)
- Tests: 5 test files (context recall, compression, diagnostics)
- Documentation: 30+ markdown files (guides, architecture, quick starts)
- Utilities: context compression, conversation parsing

Files modified:
- api/main.py: Removed router registrations
- api/models/__init__.py: Removed model imports
- api/schemas/__init__.py: Removed schema imports
- api/services/__init__.py: Removed service imports
- .claude/claude.md: Completely rewritten without context references

Database tables preserved:
- conversation_contexts, context_snippets, context_tags,
  project_states, decision_logs (5 orphaned tables remain for safety)
- Migration created but NOT applied: 20260118_172743_remove_context_system.py
- Tables can be dropped later when confirmed not needed

New files added:
- CONTEXT_SYSTEM_REMOVAL_SUMMARY.md: Detailed removal report
- CONTEXT_SYSTEM_REMOVAL_COMPLETE.md: Final status
- CONTEXT_EXPORT_RESULTS.md: Export attempt results
- scripts/export-tombstoned-contexts.py: Export tool for future use
- migrations/versions/20260118_172743_remove_context_system.py

Impact:
- Reduced from 130 to 95 API endpoints
- Reduced from 43 to 38 active database tables
- Removed 16,831 lines of code
- System fully operational without context recall

Reason for removal:
- System was not actively used (no tombstoned contexts found)
- Reduces codebase complexity
- Focuses on core MSP work tracking functionality
- Database preserved for safety (can rollback if needed)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-18 19:10:41 -07:00
parent 8bbc7737a0
commit 89e5118306
89 changed files with 7905 additions and 16831 deletions

View File

@@ -10,13 +10,10 @@ from api.models.base import Base, TimestampMixin, UUIDMixin
from api.models.billable_time import BillableTime
from api.models.client import Client
from api.models.command_run import CommandRun
from api.models.context_snippet import ContextSnippet
from api.models.conversation_context import ConversationContext
from api.models.credential import Credential
from api.models.credential_audit_log import CredentialAuditLog
from api.models.credential_permission import CredentialPermission
from api.models.database_change import DatabaseChange
from api.models.decision_log import DecisionLog
from api.models.deployment import Deployment
from api.models.environmental_insight import EnvironmentalInsight
from api.models.external_integration import ExternalIntegration
@@ -34,7 +31,6 @@ from api.models.operation_failure import OperationFailure
from api.models.pending_task import PendingTask
from api.models.problem_solution import ProblemSolution
from api.models.project import Project
from api.models.project_state import ProjectState
from api.models.schema_migration import SchemaMigration
from api.models.security_incident import SecurityIncident
from api.models.service import Service
@@ -55,13 +51,10 @@ __all__ = [
"BillableTime",
"Client",
"CommandRun",
"ContextSnippet",
"ConversationContext",
"Credential",
"CredentialAuditLog",
"CredentialPermission",
"DatabaseChange",
"DecisionLog",
"Deployment",
"EnvironmentalInsight",
"ExternalIntegration",
@@ -79,7 +72,6 @@ __all__ = [
"PendingTask",
"ProblemSolution",
"Project",
"ProjectState",
"SchemaMigration",
"SecurityIncident",
"Service",

View File

@@ -1,124 +0,0 @@
"""
ContextSnippet model for storing reusable context snippets.
Stores small, highly compressed pieces of information like technical decisions,
configurations, patterns, and lessons learned for quick retrieval.
"""
from typing import TYPE_CHECKING, Optional
from sqlalchemy import Float, ForeignKey, Index, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin, UUIDMixin
if TYPE_CHECKING:
from .client import Client
from .project import Project
class ContextSnippet(Base, UUIDMixin, TimestampMixin):
"""
ContextSnippet model for storing reusable context snippets.
Stores small, highly compressed pieces of information like technical
decisions, configurations, patterns, and lessons learned. These snippets
are designed for quick retrieval and reuse across conversations.
Attributes:
category: Category of snippet (tech_decision, configuration, pattern, lesson_learned)
title: Brief title describing the snippet
dense_content: Highly compressed information content
structured_data: JSON object for optional structured representation
tags: JSON array of tags for retrieval and categorization
project_id: Foreign key to projects (optional)
client_id: Foreign key to clients (optional)
relevance_score: Float score for ranking relevance (default 1.0)
usage_count: Integer count of how many times this snippet was retrieved (default 0)
project: Relationship to Project model
client: Relationship to Client model
"""
__tablename__ = "context_snippets"
# Foreign keys
project_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("projects.id", ondelete="SET NULL"),
doc="Foreign key to projects (optional)"
)
client_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("clients.id", ondelete="SET NULL"),
doc="Foreign key to clients (optional)"
)
# Snippet metadata
category: Mapped[str] = mapped_column(
String(100),
nullable=False,
doc="Category: tech_decision, configuration, pattern, lesson_learned"
)
title: Mapped[str] = mapped_column(
String(200),
nullable=False,
doc="Brief title describing the snippet"
)
# Content
dense_content: Mapped[str] = mapped_column(
Text,
nullable=False,
doc="Highly compressed information content"
)
structured_data: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object for optional structured representation"
)
# Retrieval metadata
tags: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of tags for retrieval and categorization"
)
relevance_score: Mapped[float] = mapped_column(
Float,
default=1.0,
server_default="1.0",
doc="Float score for ranking relevance (default 1.0)"
)
usage_count: Mapped[int] = mapped_column(
Integer,
default=0,
server_default="0",
doc="Integer count of how many times this snippet was retrieved"
)
# Relationships
project: Mapped[Optional["Project"]] = relationship(
"Project",
doc="Relationship to Project model"
)
client: Mapped[Optional["Client"]] = relationship(
"Client",
doc="Relationship to Client model"
)
# Indexes
__table_args__ = (
Index("idx_context_snippets_project", "project_id"),
Index("idx_context_snippets_client", "client_id"),
Index("idx_context_snippets_category", "category"),
Index("idx_context_snippets_relevance", "relevance_score"),
Index("idx_context_snippets_usage", "usage_count"),
)
def __repr__(self) -> str:
"""String representation of the context snippet."""
return f"<ContextSnippet(title='{self.title}', category='{self.category}', usage={self.usage_count})>"

View File

@@ -1,135 +0,0 @@
"""
ConversationContext model for storing Claude's conversation context.
Stores compressed summaries of conversations, sessions, and project states
for cross-machine recall and context continuity.
"""
from typing import TYPE_CHECKING, Optional
from sqlalchemy import Float, ForeignKey, Index, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin, UUIDMixin
if TYPE_CHECKING:
from .machine import Machine
from .project import Project
from .session import Session
class ConversationContext(Base, UUIDMixin, TimestampMixin):
"""
ConversationContext model for storing Claude's conversation context.
Stores compressed, structured summaries of conversations, work sessions,
and project states to enable Claude to recall important context across
different machines and conversation sessions.
Attributes:
session_id: Foreign key to sessions (optional - not all contexts are work sessions)
project_id: Foreign key to projects (optional)
context_type: Type of context (session_summary, project_state, general_context)
title: Brief title describing the context
dense_summary: Compressed, structured summary (JSON or dense text)
key_decisions: JSON array of important decisions made
current_state: JSON object describing what's currently in progress
tags: JSON array of tags for retrieval and categorization
relevance_score: Float score for ranking relevance (default 1.0)
machine_id: Foreign key to machines (which machine created this context)
session: Relationship to Session model
project: Relationship to Project model
machine: Relationship to Machine model
"""
__tablename__ = "conversation_contexts"
# Foreign keys
session_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("sessions.id", ondelete="SET NULL"),
doc="Foreign key to sessions (optional - not all contexts are work sessions)"
)
project_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("projects.id", ondelete="SET NULL"),
doc="Foreign key to projects (optional)"
)
machine_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("machines.id", ondelete="SET NULL"),
doc="Foreign key to machines (which machine created this context)"
)
# Context metadata
context_type: Mapped[str] = mapped_column(
String(50),
nullable=False,
doc="Type of context: session_summary, project_state, general_context"
)
title: Mapped[str] = mapped_column(
String(200),
nullable=False,
doc="Brief title describing the context"
)
# Context content
dense_summary: Mapped[Optional[str]] = mapped_column(
Text,
doc="Compressed, structured summary (JSON or dense text)"
)
key_decisions: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of important decisions made"
)
current_state: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object describing what's currently in progress"
)
# Retrieval metadata
tags: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of tags for retrieval and categorization"
)
relevance_score: Mapped[float] = mapped_column(
Float,
default=1.0,
server_default="1.0",
doc="Float score for ranking relevance (default 1.0)"
)
# Relationships
session: Mapped[Optional["Session"]] = relationship(
"Session",
doc="Relationship to Session model"
)
project: Mapped[Optional["Project"]] = relationship(
"Project",
doc="Relationship to Project model"
)
machine: Mapped[Optional["Machine"]] = relationship(
"Machine",
doc="Relationship to Machine model"
)
# Indexes
__table_args__ = (
Index("idx_conversation_contexts_session", "session_id"),
Index("idx_conversation_contexts_project", "project_id"),
Index("idx_conversation_contexts_machine", "machine_id"),
Index("idx_conversation_contexts_type", "context_type"),
Index("idx_conversation_contexts_relevance", "relevance_score"),
)
def __repr__(self) -> str:
"""String representation of the conversation context."""
return f"<ConversationContext(title='{self.title}', type='{self.context_type}', relevance={self.relevance_score})>"

View File

@@ -1,115 +0,0 @@
"""
DecisionLog model for tracking important decisions made during work.
Stores decisions with their rationale, alternatives considered, and impact
to provide decision history and context for future work.
"""
from typing import TYPE_CHECKING, Optional
from sqlalchemy import ForeignKey, Index, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin, UUIDMixin
if TYPE_CHECKING:
from .project import Project
from .session import Session
class DecisionLog(Base, UUIDMixin, TimestampMixin):
"""
DecisionLog model for tracking important decisions made during work.
Stores decisions with their type, rationale, alternatives considered,
and impact assessment. This provides a decision history that can be
referenced in future conversations and work sessions.
Attributes:
decision_type: Type of decision (technical, architectural, process, security)
decision_text: What was decided (the actual decision)
rationale: Why this decision was made
alternatives_considered: JSON array of other options that were considered
impact: Impact level (low, medium, high, critical)
project_id: Foreign key to projects (optional)
session_id: Foreign key to sessions (optional)
tags: JSON array of tags for retrieval and categorization
project: Relationship to Project model
session: Relationship to Session model
"""
__tablename__ = "decision_logs"
# Foreign keys
project_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("projects.id", ondelete="SET NULL"),
doc="Foreign key to projects (optional)"
)
session_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("sessions.id", ondelete="SET NULL"),
doc="Foreign key to sessions (optional)"
)
# Decision metadata
decision_type: Mapped[str] = mapped_column(
String(100),
nullable=False,
doc="Type of decision: technical, architectural, process, security"
)
impact: Mapped[str] = mapped_column(
String(50),
default="medium",
server_default="medium",
doc="Impact level: low, medium, high, critical"
)
# Decision content
decision_text: Mapped[str] = mapped_column(
Text,
nullable=False,
doc="What was decided (the actual decision)"
)
rationale: Mapped[Optional[str]] = mapped_column(
Text,
doc="Why this decision was made"
)
alternatives_considered: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of other options that were considered"
)
# Retrieval metadata
tags: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of tags for retrieval and categorization"
)
# Relationships
project: Mapped[Optional["Project"]] = relationship(
"Project",
doc="Relationship to Project model"
)
session: Mapped[Optional["Session"]] = relationship(
"Session",
doc="Relationship to Session model"
)
# Indexes
__table_args__ = (
Index("idx_decision_logs_project", "project_id"),
Index("idx_decision_logs_session", "session_id"),
Index("idx_decision_logs_type", "decision_type"),
Index("idx_decision_logs_impact", "impact"),
)
def __repr__(self) -> str:
"""String representation of the decision log."""
decision_preview = self.decision_text[:50] + "..." if len(self.decision_text) > 50 else self.decision_text
return f"<DecisionLog(type='{self.decision_type}', impact='{self.impact}', decision='{decision_preview}')>"

View File

@@ -1,118 +0,0 @@
"""
ProjectState model for tracking current state of projects.
Stores the current phase, progress, blockers, and next actions for each project
to enable quick context retrieval when resuming work.
"""
from typing import TYPE_CHECKING, Optional
from sqlalchemy import ForeignKey, Index, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin, UUIDMixin
if TYPE_CHECKING:
from .project import Project
from .session import Session
class ProjectState(Base, UUIDMixin, TimestampMixin):
"""
ProjectState model for tracking current state of projects.
Stores the current phase, progress, blockers, next actions, and key
information about a project's state. Each project has exactly one
ProjectState record that is updated as the project progresses.
Attributes:
project_id: Foreign key to projects (required, unique - one state per project)
current_phase: Current phase or stage of the project
progress_percentage: Integer percentage of completion (0-100)
blockers: JSON array of current blockers preventing progress
next_actions: JSON array of next steps to take
context_summary: Dense overview text of where the project currently stands
key_files: JSON array of important file paths for this project
important_decisions: JSON array of key decisions made for this project
last_session_id: Foreign key to the last session that updated this state
project: Relationship to Project model
last_session: Relationship to Session model
"""
__tablename__ = "project_states"
# Foreign keys
project_id: Mapped[str] = mapped_column(
String(36),
ForeignKey("projects.id", ondelete="CASCADE"),
nullable=False,
unique=True,
doc="Foreign key to projects (required, unique - one state per project)"
)
last_session_id: Mapped[Optional[str]] = mapped_column(
String(36),
ForeignKey("sessions.id", ondelete="SET NULL"),
doc="Foreign key to the last session that updated this state"
)
# State metadata
current_phase: Mapped[Optional[str]] = mapped_column(
String(100),
doc="Current phase or stage of the project"
)
progress_percentage: Mapped[int] = mapped_column(
Integer,
default=0,
server_default="0",
doc="Integer percentage of completion (0-100)"
)
# State content
blockers: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of current blockers preventing progress"
)
next_actions: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of next steps to take"
)
context_summary: Mapped[Optional[str]] = mapped_column(
Text,
doc="Dense overview text of where the project currently stands"
)
key_files: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of important file paths for this project"
)
important_decisions: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of key decisions made for this project"
)
# Relationships
project: Mapped["Project"] = relationship(
"Project",
doc="Relationship to Project model"
)
last_session: Mapped[Optional["Session"]] = relationship(
"Session",
doc="Relationship to Session model"
)
# Indexes
__table_args__ = (
Index("idx_project_states_project", "project_id"),
Index("idx_project_states_last_session", "last_session_id"),
Index("idx_project_states_progress", "progress_percentage"),
)
def __repr__(self) -> str:
"""String representation of the project state."""
return f"<ProjectState(project_id='{self.project_id}', phase='{self.current_phase}', progress={self.progress_percentage}%)>"