Skip to main content

Overview

Hot reloading allows you to update skills at runtime without restarting the FastSkill service. This feature is essential for development workflows where you need to iterate quickly on skill implementations.
Hot reloading is primarily intended for development environments. Consider disabling it in production for better performance and security.

How Hot Reloading Works

Configuration

Enable Hot Reloading

from fastskill import ServiceConfig
from pathlib import Path

config = ServiceConfig(
    enable_hot_reload=True,
    watch_paths=[
        Path("./skills"),                    # Main skills directory
        Path("./custom-skills"),             # Custom skills
        Path("../shared-skills"),            # Shared skills
        Path("./experimental-skills")        # Experimental features
    ],
    hot_reload_config={
        "debounce_seconds": 1,               # Wait 1s after changes
        "max_watch_depth": 5,                # Max directory depth
        "ignore_patterns": [".git", "__pycache__", "*.tmp"],
        "include_patterns": ["*.py", "*.json", "*.md", "*.yaml"]
    }
)

File Watching

Configure which files and directories to watch:
# Watch specific file types
config = ServiceConfig(
    enable_hot_reload=True,
    watch_paths=[Path("./skills")],
    watch_patterns={
        "include": ["*.py", "*.json", "*.yaml", "*.md"],
        "exclude": [".git", "__pycache__", "*.pyc", ".DS_Store"],
        "recursive": True,
        "follow_symlinks": False
    }
)

Development Workflow

1. Setup Hot Reloading

async def setup_development():
    """Setup development environment with hot reloading."""

    # Configure for development
    config = ServiceConfig(
        skill_storage_path=Path("./skills"),
        enable_hot_reload=True,
        watch_paths=[Path("./skills")],
        log_level="DEBUG",
        enable_audit_logging=True,
        cache=CacheConfig(
            cache_ttl_seconds=60  # Short cache for development
        )
    )

    # Initialize service
    service = FastSkillService(config)
    await service.initialize()

    print("πŸ”₯ Hot reloading enabled!")
    print("πŸ“ Watching directories: ./skills")
    print("πŸ“ Edit skills and see changes automatically")

    # Keep service running
    try:
        while True:
            await asyncio.sleep(1)
    except KeyboardInterrupt:
        await service.shutdown()
        print("\nπŸ‘‹ Development session ended")

2. Create and Update Skills

# Example: Create a simple skill
skill_definition = {
    "id": "hello-world",
    "name": "Hello World",
    "description": "A simple hello world skill",
    "version": "1.0.0",
    "tags": "demo,hello",
    "capabilities": "text_generation",
    "skill_file": "hello_skill.py",
    "enabled": True
}

# Create implementation file
with open("skills/hello_skill.py", "w") as f:
    f.write('''
async def say_hello(name: str = "World") -> dict:
    """Say hello to someone."""
    return {
        "success": True,
        "message": f"Hello, {name}!",
        "timestamp": "2024-01-15T10:30:00Z"
    }
''')

# Register skill
await service.register_skill(skill_definition)

# Test the skill
result = await service.tool_service.execute_tool(
    "hello-world",
    "say_hello",
    {"name": "Developer"}
)
print(f"Result: {result}")

3. Live Updates

# Edit the skill file and see changes immediately
# skills/hello_skill.py - updated version
with open("skills/hello_skill.py", "w") as f:
    f.write('''
async def say_hello(name: str = "World") -> dict:
    """Say hello with enthusiasm!"""
    return {
        "success": True,
        "message": f"Hello, {name}! πŸŽ‰",
        "timestamp": "2024-01-15T10:30:00Z",
        "enhanced": True  # New feature!
    }

async def say_goodbye(name: str = "World") -> dict:
    """Say goodbye to someone."""
    return {
        "success": True,
        "message": f"Goodbye, {name}! πŸ‘‹",
        "timestamp": "2024-01-15T10:30:00Z"
    }
''')

# The skill is automatically reloaded!
# New tools and updated functionality are available immediately
result1 = await service.tool_service.execute_tool(
    "hello-world",
    "say_hello",
    {"name": "Developer"}
)

result2 = await service.tool_service.execute_tool(
    "hello-world",
    "say_goodbye",  # New tool!
    {"name": "Developer"}
)

Event Handling

Subscribe to hot reload events:
async def handle_reload_events():
    """Handle hot reload events."""

    def on_skill_reloaded(event):
        print(f"πŸ”„ Skill reloaded: {event['skill_id']}")
        print(f"   Version: {event['new_version']}")
        print(f"   Changes: {event['changes']}")

    def on_reload_error(event):
        print(f"❌ Reload error: {event['skill_id']}")
        print(f"   Error: {event['error']}")
        print(f"   File: {event['file_path']}")

    def on_validation_error(event):
        print(f"⚠️ Validation error: {event['skill_id']}")
        for error in event['validation_errors']:
            print(f"   {error['field']}: {error['message']}")

    # Subscribe to events
    service.subscribe("skill.reloaded", on_skill_reloaded)
    service.subscribe("skill.reload_error", on_reload_error)
    service.subscribe("skill.validation_error", on_validation_error)

    # Events are triggered automatically when files change

Monitoring Hot Reloading

Performance Metrics

async def monitor_hot_reload():
    """Monitor hot reload performance."""

    metrics = await service.get_hot_reload_metrics()

    print("πŸ“Š Hot Reload Metrics:")
    print(f"   Files watched: {metrics['files_watched']}")
    print(f"   Reloads performed: {metrics['reloads_performed']}")
    print(f"   Average reload time: {metrics['avg_reload_time_ms']:.2f}ms")
    print(f"   Errors: {metrics['reload_errors']}")
    print(f"   Cache hit rate: {metrics['cache_hit_rate']:.1%}")

    # Recent reloads
    recent = metrics['recent_reloads']
    print(f"\n⏰ Recent reloads:")
    for reload_event in recent[-5:]:  # Last 5 reloads
        print(f"   {reload_event['timestamp']}: {reload_event['skill_id']} ({reload_event['duration_ms']}ms)")

Debug Mode

Enable debug mode for detailed hot reload information:
# Enable debug logging for hot reload
export FASTSKILL_LOG_LEVEL=DEBUG
fastskill serve --hot-reload --debug

# Monitor file changes in real-time
fastskill serve --hot-reload --watch-verbose

Production Considerations

Disable in Production

# Production configuration - hot reload disabled
config = ServiceConfig(
    enable_hot_reload=False,  # Disable for security and performance
    log_level="INFO",         # Reduce verbosity
    enable_audit_logging=True # Keep audit trail
)

Conditional Reloading

Enable hot reloading only for specific skills or environments:
config = ServiceConfig(
    enable_hot_reload=True,
    hot_reload_config={
        "allowed_skills": ["dev-*", "test-*"],  # Only reload dev/test skills
        "require_auth": True,                   # Require authentication
        "max_reload_rate": 10,                   # Max reloads per minute
        "enable_validation": True               # Validate before reload
    }
)

File Change Detection

Supported File Types

Hot reloading monitors these file types by default:
ExtensionPurposeReload Trigger
.pyPython implementationFunction signature or behavior changes
.jsonSkill definitionsMetadata or configuration changes
.yamlConfiguration filesSettings or parameter changes
.mdDocumentationHelp text or description updates

Change Detection Rules

# Configure change detection
config = ServiceConfig(
    enable_hot_reload=True,
    hot_reload_config={
        "change_detection": {
            "function_signature_only": False,  # Reload on any code change
            "ignore_comments": True,           # Don't reload for comment changes
            "ignore_whitespace": True,         # Don't reload for formatting changes
            "require_restart": ["dependencies", "execution_timeout"]  # Require restart for these
        }
    }
)

Integration with Development Tools

IDE Integration

# VS Code extension integration
class FastSkillExtension:
    """VS Code extension for FastSkill development."""

    def on_file_saved(self, file_path: str):
        """Called when a skill file is saved."""
        if self.is_skill_file(file_path):
            # Trigger validation
            validation_result = self.validate_skill_file(file_path)

            if validation_result["valid"]:
                # Show success notification
                self.show_notification("βœ… Skill updated successfully")
            else:
                # Show validation errors
                self.show_errors(validation_result["errors"])

    def on_hot_reload_event(self, event: dict):
        """Handle hot reload events."""
        if event["type"] == "skill_reloaded":
            self.update_problems_view(event["skill_id"], [])
            self.refresh_skill_tree()
        elif event["type"] == "reload_error":
            self.update_problems_view(event["skill_id"], [event["error"]])

Live Testing

# Integration with pytest-watch
async def live_testing_integration():
    """Integrate hot reloading with live testing."""

    import subprocess
    import time

    def run_tests():
        """Run tests when skills change."""
        result = subprocess.run(
            ["pytest", "tests/", "-v", "--tb=short"],
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            print("βœ… All tests passed")
        else:
            print("❌ Tests failed:")
            print(result.stdout)
            print(result.stderr)

    def on_skill_changed(event):
        """Run tests when skills change."""
        print(f"πŸ”„ Skill changed: {event['skill_id']}")
        print("πŸ§ͺ Running tests...")

        # Debounce test runs
        time.sleep(2)  # Wait for any additional changes
        run_tests()

    # Subscribe to skill changes
    service.subscribe("skill.reloaded", on_skill_changed)
    service.subscribe("skill.registered", on_skill_changed)

Troubleshooting

Check configuration: Ensure hot reload is enabled and watch paths are correct.
# Verify configuration
config = service.get_config()
print(f"Hot reload enabled: {config.enable_hot_reload}")
print(f"Watch paths: {config.watch_paths}")
File permissions: Ensure FastSkill has read permissions for watched directories.
# Fix permissions
chmod 755 ./skills/
chmod 644 ./skills/*.py
Optimize watch paths: Limit the number of directories and files being watched.
config = ServiceConfig(
    watch_paths=[Path("./skills")],  # Single directory
    hot_reload_config={
        "include_patterns": ["*.py", "*.json"]  # Only essential files
    }
)
Increase debounce time: Add delay to batch multiple file changes.
config = ServiceConfig(
    hot_reload_config={"debounce_seconds": 2}
)
Check file syntax: Ensure updated files have valid syntax before saving.
# Validate Python files
python -m py_compile skills/skill.py

# Validate JSON files
python -c "import json; json.load(open('skill.json'))"
Review error logs: Check service logs for detailed validation error information.
fastskill logs --level DEBUG --follow

Best Practices

1

Use development-only skills

Create separate skills for development with β€œdev-” prefix to avoid affecting production.
2

Test thoroughly

Run comprehensive tests after hot reload to ensure functionality still works.
3

Monitor performance

Keep an eye on reload times and memory usage during development.
4

Version control integration

Ensure hot reload changes are properly tracked in version control.
5

Disable in production

Always disable hot reload in production environments for security and performance.
Hot reloading dramatically improves development experience by eliminating the need to restart services. Use it during development but disable it in production environments.