<!--
hoody-tunnel Subskill (sdk)
Auto-generated by Hoody Skills Generator
Generated: 2026-06-20T00:07:51.496Z
Model: mimo-v2.5-pro
Mode: sdk


Tokens: 5284

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-tunnel Subskill

## Overview

**Service Purpose**: Hoody Tunnel provides secure, multiplexed tunnel connections between local development environments and containerized services running in Hoody Kit. It handles WebSocket control planes, manages active bindings and sessions, and exposes metrics for monitoring tunnel health and performance.

**When to Use**:
- When establishing multiplexed WebSocket tunnels to containerized services
- When monitoring active tunnel sessions, bindings, and metrics
- When needing to terminate specific tunnel sessions for maintenance or troubleshooting
- When integrating local development tools with remote Hoody services

**Philosophy Alignment**: Hoody Tunnel embodies the "zero configuration" philosophy by automatically handling secure connections without manual DNS or network configuration. It provides service isolation, multi-tenant support, and built-in authentication through the Hoody API.

**Architecture Notes**:
- Uses WebSocket multiplexing for efficient bidirectional communication
- Supports protocol versions `hoody-tunnel.v1` and `hoody-tunnel.v2`
- Integrates with Hoody Proxy routing system for service discovery
- Provides standard Prometheus metrics for observability

## Common Workflows

### Monitoring Tunnel Health and Status

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ 
  baseURL: 'https://api.hoody.com', 
  token: 'YOUR_TOKEN' 
})

// Check service health (no authentication required)
async function checkHealth() {
  const health = await client.tunnel.health.check()
  console.log('Service status:', health.status)
  console.log('Memory usage:', health.memory)
  console.log('File descriptors:', health.fds)
  return health
}

// List all active tunnel sessions
async function listActiveSessions() {
  const sessions = await client.tunnel.listSessions()
  console.log('Active sessions:', sessions.length)
  
  sessions.forEach(session => {
    console.log(`Session ${session.id}: ${session.bindings?.length} bindings, ${session.streams} streams`)
  })
  return sessions
}

// Get comprehensive tunnel overview
async function getTunnelOverview() {
  const overview = await client.tunnel.listTunnels()
  console.log('Total tunnels:', overview.tunnels?.length)
  console.log('Orphan streams:', overview.orphans)
  console.log('FD budget status:', overview.fd_budget)
  return overview
}
```

### Managing Active Bindings

```
// View all active bindings across sessions
async function viewBindings() {
  const bindings = await client.tunnel.listBindings()
  
  bindings.forEach(binding => {
    console.log(`Binding ${binding.bind_id}: ${binding.kind} ${binding.mode}`)
    console.log(`  Session: ${binding.session_id}`)
    console.log(`  Port: ${binding.port}`)
  })
  return bindings
}

// Check Prometheus metrics for monitoring
async function getMetrics() {
  const metrics = await client.tunnel.getMetrics()
  console.log('Metrics (Prometheus format):')
  console.log(metrics)
  return metrics
}
```

### Session Lifecycle Management

```
// Terminate a specific session
async function terminateSession(sessionId: string) {
  console.log(`Terminating session: ${sessionId}`)
  
  const result = await client.tunnel.killSession(sessionId, 1000) // 1 second grace period
  console.log('Kill result:', result.status)
  
  // Verify session is no longer active
  const sessions = await client.tunnel.listSessions()
  const sessionExists = sessions.some(s => s.id === sessionId)
  console.log('Session still exists:', sessionExists)
  
  return result
}

// Force-close stuck sessions
async function forceCloseStuckSessions() {
  const sessions = await client.tunnel.listSessions()
  const stuckSessions = sessions.filter(s => s.streams > 0 && s.status === 'idle')
  
  console.log(`Found ${stuckSessions.length} potentially stuck sessions`)
  
  for (const session of stuckSessions) {
    await client.tunnel.killSession(session.id, 0) // Zero grace for force close
  }
  
  return stuckSessions.length
}
```

### WebSocket Connection Setup

```
// Note: WebSocket connection establishment is handled through the control plane
// The actual connection details are managed by the SDK internally

// Initialize tunnel connection (control plane)
async function initializeTunnel() {
  console.log('Initializing tunnel control plane...')
  const result = await client.tunnel.tunnelConnect()
  console.log('Tunnel control plane initialized:', result)
  return result
}
```

## Advanced Operations

### Error Recovery Patterns

```
// Recover from connection failures
async function recoverFromFailures() {
  try {
    // Attempt to establish connection
    await client.tunnel.tunnelConnect()
  } catch (error) {
    console.error('Connection failed, checking health...')
    
    const health = await client.tunnel.health.check()
    if (health.status !== 'ready') {
      console.error('Service not ready, status:', health.status)
      throw new Error('Service unavailable')
    }
    
    // Retry connection
    console.log('Retrying connection...')
    return await client.tunnel.tunnelConnect()
  }
}

// Handle session cleanup during failures
async function cleanupFailedSession(sessionId: string) {
  try {
    // First try graceful termination
    await client.tunnel.killSession(sessionId, 5000)
    console.log('Graceful termination successful')
  } catch (error) {
    console.error('Graceful termination failed, force closing...')
    
    // Force close with zero grace period
    await client.tunnel.killSession(sessionId, 0)
    console.log('Force termination completed')
  }
  
  // Verify cleanup
  const sessions = await client.tunnel.listSessions()
  return !sessions.some(s => s.id === sessionId)
}
```

### Performance Monitoring and Optimization

```
// Monitor tunnel performance over time
async function monitorPerformance() {
  const metrics = await client.tunnel.getMetrics()
  
  // Parse Prometheus metrics for analysis
  const lines = metrics.split('\n')
  const activeSessions = lines.find(l => l.includes('hoody_tunnel_sessions_active'))
  const activeBindings = lines.find(l => l.includes('hoody_tunnel_bindings_active'))
  
  console.log('Active sessions:', activeSessions?.split(' ')[1] || '0')
  console.log('Active bindings:', activeBindings?.split(' ')[1] || '0')
  
  return { activeSessions, activeBindings }
}

// Load balancing across sessions
async function balanceSessionLoad() {
  const sessions = await client.tunnel.listSessions()
  const bindings = await client.tunnel.listBindings()
  
  // Identify sessions with high binding counts
  const highLoadSessions = sessions.filter(s => 
    s.bindings && s.bindings.length > 10
  )
  
  console.log(`Sessions with high load: ${highLoadSessions.length}`)
  
  // Consider terminating oldest high-load sessions if needed
  if (highLoadSessions.length > 3) {
    console.log('Consider load balancing by terminating older sessions')
  }
  
  return { sessions, bindings, highLoadSessions }
}
```

### Multi-Session Coordination

```
// Coordinate multiple tunnel sessions
async function coordinateSessions() {
  const sessions = await client.tunnel.listSessions()
  const overview = await client.tunnel.listTunnels()
  
  // Check for orphan streams
  if (overview.orphans > 0) {
    console.log(`Found ${overview.orphans} orphan streams, cleaning up...`)
    // Implementation would involve identifying and closing orphan connections
  }
  
  // Check FD budget
  if (overview.fd_budget?.usage > 0.8) {
    console.log('FD usage above 80%, consider scaling or optimization')
  }
  
  return {
    sessionCount: sessions.length,
    orphanStreams: overview.orphans,
    fdUsage: overview.fd_budget?.usage
  }
}
```

## Quick Reference

### Essential Endpoints

| Method | Endpoint | Purpose | SDK Method |
|--------|----------|---------|------------|
| GET | `/api/v1/tunnel/bindings` | List active bindings | `client.tunnel.listBindings()` |
| GET | `/api/v1/tunnel/connect` | WebSocket control plane | `client.tunnel.tunnelConnect()` |
| GET | `/api/v1/tunnel/health` | Service health check | `client.tunnel.health.check()` |
| GET | `/api/v1/tunnel/metrics` | Prometheus metrics | `client.tunnel.getMetrics()` |
| GET | `/api/v1/tunnel/sessions` | List active sessions | `client.tunnel.listSessions()` |
| DELETE | `/api/v1/tunnel/sessions/{session_id}` | Terminate session | `client.tunnel.killSession(session_id, grace_ms)` |
| GET | `/api/v1/tunnel/tunnels` | Combined tunnel overview | `client.tunnel.listTunnels()` |

### Essential Parameters

**DELETE `/api/v1/tunnel/sessions/{session_id}`**
- **session_id** (required): String - ID of the session to terminate
- **grace_ms** (optional): Integer - Grace period in milliseconds (default: 0 for force close)

### Typical Response Formats

**Health Response**:
```
{
  "status": "ready",
  "service": "hoody-tunnel",
  "built": "2025-11-05T12:00:00Z",
  "started": "2025-11-05T14:30:00Z",
  "memory": "125MB",
  "fds": 42,
  "pid": 12345,
  "ip": "10.0.0.1",
  "userAgent": "hoody-tunnel/1.0"
}
```

**Sessions Response**:
```
[
  {
    "id": "sess_abc123",
    "protocol_version": "hoody-tunnel.v2",
    "streams": 5,
    "bindings": [
      {
        "bind_id": "bind_xyz789",
        "port": 8080,
        "kind": "expose",
        "mode": "pull"
      }
    ],
    "started_at": "2025-11-05T15:00:00Z"
  }
]
```

**Kill Response**:
```
{
  "status": "terminated",
  "session_id": "sess_abc123",
  "grace_applied_ms": 1000
}
```

### Workflow Checklist
- ✅ Always check service health before critical operations
- ✅ Use `listSessions()` to verify session state before termination
- ✅ Monitor metrics periodically for performance issues
- ✅ Implement proper error handling for connection failures
- ✅ Use appropriate grace periods for session termination
- ✅ Check FD budget when experiencing connection issues

**Note**: For actual tunnel establishment and data transfer, refer to the core SKILL.md for container creation and service discovery. Hoody Tunnel provides the control plane and monitoring for these connections.