Files
claudetools/api/models/machine.py
Mike Swanson 390b10b32c Complete Phase 6: MSP Work Tracking with Context Recall System
Implements production-ready MSP platform with cross-machine persistent memory for Claude.

API Implementation:
- 130 REST API endpoints across 21 entities
- JWT authentication on all endpoints
- AES-256-GCM encryption for credentials
- Automatic audit logging
- Complete OpenAPI documentation

Database:
- 43 tables in MariaDB (172.16.3.20:3306)
- 42 SQLAlchemy models with modern 2.0 syntax
- Full Alembic migration system
- 99.1% CRUD test pass rate

Context Recall System (Phase 6):
- Cross-machine persistent memory via database
- Automatic context injection via Claude Code hooks
- Automatic context saving after task completion
- 90-95% token reduction with compression utilities
- Relevance scoring with time decay
- Tag-based semantic search
- One-command setup script

Security Features:
- JWT tokens with Argon2 password hashing
- AES-256-GCM encryption for all sensitive data
- Comprehensive audit trail for credentials
- HMAC tamper detection
- Secure configuration management

Test Results:
- Phase 3: 38/38 CRUD tests passing (100%)
- Phase 4: 34/35 core API tests passing (97.1%)
- Phase 5: 62/62 extended API tests passing (100%)
- Phase 6: 10/10 compression tests passing (100%)
- Overall: 144/145 tests passing (99.3%)

Documentation:
- Comprehensive architecture guides
- Setup automation scripts
- API documentation at /api/docs
- Complete test reports
- Troubleshooting guides

Project Status: 95% Complete (Production-Ready)
Phase 7 (optional work context APIs) remains for future enhancement.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 06:00:26 -07:00

264 lines
8.1 KiB
Python

"""
Machine model for technician's machines used for MSP work.
Tracks laptops, desktops, and workstations with their capabilities,
installed tools, MCP servers, and skills.
"""
from datetime import datetime
from typing import TYPE_CHECKING, Optional
from sqlalchemy import Boolean, Index, Integer, String, Text, TIMESTAMP
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .base import Base, TimestampMixin, UUIDMixin
if TYPE_CHECKING:
from .session import Session
class Machine(Base, UUIDMixin, TimestampMixin):
"""
Machine model representing technician's machines used for MSP work.
Tracks machine identification, capabilities, installed tools, MCP servers,
skills, and network context. Machines are auto-detected on session start
using hostname, username, platform, and home directory.
Attributes:
hostname: Machine hostname from `hostname` command
machine_fingerprint: SHA256 hash of hostname + username + platform + home_directory
friendly_name: Human-readable name like "Main Laptop" or "Home Desktop"
machine_type: Type of machine (laptop, desktop, workstation, vm)
platform: Operating system platform (win32, darwin, linux)
os_version: Operating system version
username: Username from `whoami` command
home_directory: User home directory path
has_vpn_access: Whether machine can connect to client networks
vpn_profiles: JSON array of available VPN profiles
has_docker: Whether Docker is installed
has_powershell: Whether PowerShell is installed
powershell_version: PowerShell version if installed
has_ssh: Whether SSH is available
has_git: Whether Git is installed
typical_network_location: Typical network location (home, office, mobile)
static_ip: Static IP address if applicable
claude_working_directory: Primary working directory for Claude Code
additional_working_dirs: JSON array of additional working directories
installed_tools: JSON object with tool versions
available_mcps: JSON array of available MCP servers
mcp_capabilities: JSON object with MCP capabilities
available_skills: JSON array of available skills
skill_paths: JSON object mapping skill names to paths
preferred_shell: Preferred shell (powershell, bash, zsh, cmd)
package_manager_commands: JSON object with package manager commands
is_primary: Whether this is the primary machine
is_active: Whether machine is active
last_seen: Last time machine was seen
last_session_id: UUID of last session from this machine
notes: Additional notes about the machine
"""
__tablename__ = "machines"
# Machine identification (auto-detected)
hostname: Mapped[str] = mapped_column(
String(255),
nullable=False,
unique=True,
doc="Machine hostname from `hostname` command"
)
machine_fingerprint: Mapped[Optional[str]] = mapped_column(
String(500),
unique=True,
doc="SHA256 hash: hostname + username + platform + home_directory"
)
# Environment details
friendly_name: Mapped[Optional[str]] = mapped_column(
String(255),
doc="Human-readable name like 'Main Laptop' or 'Home Desktop'"
)
machine_type: Mapped[Optional[str]] = mapped_column(
String(50),
doc="Type of machine: laptop, desktop, workstation, vm"
)
platform: Mapped[Optional[str]] = mapped_column(
String(50),
doc="Operating system platform: win32, darwin, linux"
)
os_version: Mapped[Optional[str]] = mapped_column(
String(100),
doc="Operating system version"
)
username: Mapped[Optional[str]] = mapped_column(
String(255),
doc="Username from `whoami` command"
)
home_directory: Mapped[Optional[str]] = mapped_column(
String(500),
doc="User home directory path"
)
# Capabilities
has_vpn_access: Mapped[bool] = mapped_column(
Boolean,
default=False,
server_default="0",
doc="Whether machine can connect to client networks"
)
vpn_profiles: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of available VPN profiles"
)
has_docker: Mapped[bool] = mapped_column(
Boolean,
default=False,
server_default="0",
doc="Whether Docker is installed"
)
has_powershell: Mapped[bool] = mapped_column(
Boolean,
default=False,
server_default="0",
doc="Whether PowerShell is installed"
)
powershell_version: Mapped[Optional[str]] = mapped_column(
String(20),
doc="PowerShell version if installed"
)
has_ssh: Mapped[bool] = mapped_column(
Boolean,
default=True,
server_default="1",
doc="Whether SSH is available"
)
has_git: Mapped[bool] = mapped_column(
Boolean,
default=True,
server_default="1",
doc="Whether Git is installed"
)
# Network context
typical_network_location: Mapped[Optional[str]] = mapped_column(
String(100),
doc="Typical network location: home, office, mobile"
)
static_ip: Mapped[Optional[str]] = mapped_column(
String(45),
doc="Static IP address if applicable (supports IPv4/IPv6)"
)
# Claude Code context
claude_working_directory: Mapped[Optional[str]] = mapped_column(
String(500),
doc="Primary working directory for Claude Code"
)
additional_working_dirs: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of additional working directories"
)
# Tool versions
installed_tools: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object with tool versions like {\"git\": \"2.40\", \"docker\": \"24.0\"}"
)
# MCP Servers & Skills
available_mcps: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of available MCP servers"
)
mcp_capabilities: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object with MCP capabilities"
)
available_skills: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON array of available skills"
)
skill_paths: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object mapping skill names to paths"
)
# OS-Specific Commands
preferred_shell: Mapped[Optional[str]] = mapped_column(
String(50),
doc="Preferred shell: powershell, bash, zsh, cmd"
)
package_manager_commands: Mapped[Optional[str]] = mapped_column(
Text,
doc="JSON object with package manager commands"
)
# Status
is_primary: Mapped[bool] = mapped_column(
Boolean,
default=False,
server_default="0",
doc="Whether this is the primary machine"
)
is_active: Mapped[bool] = mapped_column(
Boolean,
default=True,
server_default="1",
doc="Whether machine is currently active"
)
last_seen: Mapped[Optional[datetime]] = mapped_column(
TIMESTAMP,
doc="Last time machine was seen"
)
last_session_id: Mapped[Optional[str]] = mapped_column(
String(36),
doc="UUID of last session from this machine"
)
# Notes
notes: Mapped[Optional[str]] = mapped_column(
Text,
doc="Additional notes about the machine"
)
# Relationships
sessions: Mapped[list["Session"]] = relationship(
"Session",
back_populates="machine",
doc="Sessions associated with this machine"
)
# Indexes
__table_args__ = (
Index("idx_machines_hostname", "hostname"),
Index("idx_machines_fingerprint", "machine_fingerprint"),
Index("idx_machines_is_active", "is_active"),
Index("idx_machines_platform", "platform"),
)
def __repr__(self) -> str:
"""String representation of the machine."""
return f"<Machine(hostname='{self.hostname}', friendly_name='{self.friendly_name}', platform='{self.platform}')>"