# Standalone Service Usage

This document shows how to use Styrene functionality without running the TUI. All core logic is available as standalone services that can be tested, scripted, or integrated into other tools.

## Architecture

```
┌─────────────────────────────────────┐
│   TUI (Textual App)                 │
│   - Dashboard, Settings, Provision  │
└──────────────┬──────────────────────┘
               │ uses
               ↓
┌─────────────────────────────────────┐
│   Services (No UI Dependencies)     │
│   - app_lifecycle                   │
│   - rns_service                     │
│   - hub_connection                  │
│   - reticulum                       │
│   - fleet                           │
│   - hardware                        │
│   - config                          │
└─────────────────────────────────────┘
```

**Key Principle**: Services have NO UI dependencies. They can be imported and used independently.

## CLI Tools

Styrene provides CLI tools for testing functionality without the TUI:

### Reticulum CLI

```bash
# Show Reticulum service status
python -m styrene.cli.reticulum_cli status

# Initialize services
python -m styrene.cli.reticulum_cli init

# Start device discovery (listens for announces)
python -m styrene.cli.reticulum_cli discover

# Connect to a Styrene hub
python -m styrene.cli.reticulum_cli hub-connect <64-char-hex-address>
```

**Example Output**:
```
$ python -m styrene.cli.reticulum_cli status
=== Reticulum Service Status ===
RNS Initialized: True
Operator Identity: 50260be4428db7af
Transport Enabled: False
Interface Count: 2

Hub Connected: True
Hub Address: a1b2c3d4e5f6...
```

### Fleet Management CLI

```bash
# List all devices
python -m styrene.cli.fleet_cli list

# Show fleet summary
python -m styrene.cli.fleet_cli summary

# Show device details
python -m styrene.cli.fleet_cli device <device-name>
```

**Example Output**:
```
$ python -m styrene.cli.fleet_cli summary
=== Fleet Summary ===

  Online:    3
  Offline:   1
  Pending:   1
  Error:     0
  ───────────────
  Total:     5
```

### Hardware Detection CLI

```bash
# Show system information
python -m styrene.cli.hardware_cli system

# Show disk information
python -m styrene.cli.hardware_cli disks

# Show network interfaces
python -m styrene.cli.hardware_cli network

# Show all hardware information
python -m styrene.cli.hardware_cli all
```

**Example Output**:
```
$ python -m styrene.cli.hardware_cli system
=== System Information ===

  CPU Model:    Apple M1 Max
  CPU Cores:    10
  RAM Total:    64.00 GB
```

## Python API Usage

### Quick Start: Initialize Services

```python
from styrene.services.app_lifecycle import initialize_styrene

# Initialize all Styrene services
lifecycle = initialize_styrene()

# Use services...

# Cleanup
lifecycle.shutdown()
```

### Example: Check Reticulum Status

```python
from styrene.services.app_lifecycle import get_service_status

status = get_service_status()

print(f"RNS initialized: {status['rns_initialized']}")
print(f"Hub connected: {status['hub_connected']}")
print(f"Operator identity: {status['operator_identity']}")
print(f"Transport enabled: {status['transport_enabled']}")
print(f"Interface count: {status['interface_count']}")
```

### Example: Device Discovery

```python
from styrene.services.app_lifecycle import initialize_styrene
from styrene.services.reticulum import start_discovery, discover_devices
import time

# Initialize
lifecycle = initialize_styrene()

# Define callback for discovered devices
def on_device_found(device_info):
    if device_info.get("is_styrene"):
        print(f"Styrene device: {device_info['name']}")
        print(f"  Identity: {device_info['identity'][:16]}...")
        print(f"  Announces: {device_info['announces']}")

# Start discovery
start_discovery(callback=on_device_found)

# Run for 60 seconds
time.sleep(60)

# Get all discovered devices
devices = discover_devices()
print(f"Total devices discovered: {len(devices)}")

# Cleanup
lifecycle.shutdown()
```

### Example: Fleet Management

```python
from styrene.services.fleet import load_inventory, get_fleet_summary

# Get fleet summary
summary = get_fleet_summary()
print(f"Online: {summary['online']}")
print(f"Offline: {summary['offline']}")
print(f"Total: {summary['total']}")

# Load full inventory
devices = load_inventory()
for device in devices:
    print(f"{device.name} - {device.status} - {device.ip_address}")
```

### Example: Hardware Detection

```python
from styrene.services.hardware import (
    get_system_info,
    get_disks,
    get_network_interfaces,
)

# System info
info = get_system_info()
print(f"CPU: {info.cpu_model}")
print(f"Cores: {info.cpu_cores}")
print(f"RAM: {info.ram_total_gb:.1f} GB")

# Disks
disks = get_disks()
for disk in disks:
    if disk.is_removable:
        print(f"Removable: {disk.name} ({disk.size_human})")

# Network interfaces
interfaces = get_network_interfaces()
active = [i for i in interfaces if i.is_up and i.is_hardware]
print(f"Active interfaces: {len(active)}")
```

### Example: Hub Connection

```python
from styrene.services.app_lifecycle import initialize_styrene
from styrene.services.hub_connection import get_hub_connection

# Initialize services
lifecycle = initialize_styrene()

# Connect to hub
hub_connection = get_hub_connection()
hub_address = "a1b2c3d4e5f6..."  # 64-char hex

if hub_connection.connect(hub_address):
    print(f"Connected to hub")
    print(f"Hub destination: {hub_connection.hub_destination}")
else:
    print("Connection failed")

# Cleanup
lifecycle.shutdown()
```

### Example: Configuration Management

```python
from styrene.services.config import load_config, save_config

# Load configuration
config = load_config()

# Modify
config.reticulum.hub_enabled = True
config.reticulum.hub_address = "a1b2c3d4..."

# Save
save_config(config)
```

## Testing Without TUI

All services can be tested independently:

```python
import pytest
from styrene.services.reticulum import ensure_operator_identity, get_operator_identity

def test_operator_identity_creation():
    """Test operator identity without TUI."""
    # Ensure identity exists
    identity_hash = ensure_operator_identity()
    assert identity_hash is not None
    assert len(identity_hash) == 64  # 32 bytes hex

    # Verify it can be loaded
    loaded = get_operator_identity()
    assert loaded == identity_hash
```

## Integration with Scripts

```python
#!/usr/bin/env python3
"""Example script: Monitor fleet and alert on offline devices."""

import time
from styrene.services.app_lifecycle import initialize_styrene
from styrene.services.fleet import load_inventory

# Initialize
lifecycle = initialize_styrene()

# Monitor loop
while True:
    devices = load_inventory()
    offline = [d for d in devices if d.status == "offline"]

    if offline:
        print(f"ALERT: {len(offline)} offline devices:")
        for device in offline:
            print(f"  - {device.name} (last seen: {device.last_seen_display})")

    time.sleep(300)  # Check every 5 minutes
```

## Service Reference

### StyreneLifecycle

**Purpose**: Manages application lifecycle independently of TUI.

**Methods**:
- `initialize()` → `bool` - Initialize all services
- `shutdown()` → `None` - Cleanup all services
- `is_initialized` → `bool` - Check initialization status

**Example**:
```python
from styrene.services.app_lifecycle import StyreneLifecycle
from styrene.services.config import load_config

config = load_config()
lifecycle = StyreneLifecycle(config)

if lifecycle.initialize():
    print("Services ready")
    # Use services...
    lifecycle.shutdown()
```

### get_service_status()

**Purpose**: Get current status of all services.

**Returns**: `dict[str, Any]` with keys:
- `rns_initialized` - RNS service status
- `hub_connected` - Hub connection status
- `hub_address` - Hub address if connected
- `operator_identity` - Operator identity hash
- `transport_enabled` - Transport node status
- `interface_count` - Number of configured interfaces

**Example**:
```python
from styrene.services.app_lifecycle import get_service_status

status = get_service_status()
if not status['rns_initialized']:
    print("RNS not initialized - run initialization first")
```

## Best Practices

1. **Always initialize before using services**
   ```python
   lifecycle = initialize_styrene()
   # ... use services ...
   lifecycle.shutdown()
   ```

2. **Check service status before operations**
   ```python
   status = get_service_status()
   if not status['rns_initialized']:
       print("RNS not available")
       return
   ```

3. **Use context managers for cleanup** (custom wrapper)
   ```python
   from contextlib import contextmanager

   @contextmanager
   def styrene_context():
       lifecycle = initialize_styrene()
       try:
           yield lifecycle
       finally:
           lifecycle.shutdown()

   with styrene_context():
       # Use services...
       pass
   ```

4. **Handle errors gracefully**
   ```python
   from styrene.services.fleet import FleetInventoryError

   try:
       devices = load_inventory()
   except FleetInventoryError as e:
       print(f"Fleet unavailable: {e}")
   ```

## Debugging

Enable verbose logging:

```python
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='[%(levelname)s] %(name)s: %(message)s'
)

# Now all service operations will log verbosely
lifecycle = initialize_styrene()
```

Or use CLI verbose mode:

```bash
python -m styrene.cli.reticulum_cli -v status
```

## See Also

- [TUI Development](CLAUDE.md) - TUI-specific patterns
- [Service Architecture](../src/styrene/services/) - Service implementation
- [Test Examples](../tests/services/) - Service test patterns
