<!--
hoody-code Subskill (http)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T18:33:18.851Z
Model: mimo-v2.5-pro + fixer:z-ai/glm-5.1
Mode: http


Tokens: 7201

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

# hoody-code.md

## Overview

**hoody-code** provides VS Code instances accessible via URL within Hoody containers. Each container can host multiple code instances, enabling remote development environments without local IDE setup.

### When to Use

- Remote development access to containerized projects
- Automated extension deployment and management
- Proxying local development servers through authenticated URLs
- Progressive Web App installation for offline-capable IDE access

### Hoody Philosophy Fit

hoody-code embodies Hoody's zero-configuration principle: no DNS setup, no SSL certificates, no manual authentication. Access follows the standard Hoody Kit URL pattern with automatic proxy routing and built-in authentication.

### Base URL Pattern

```
https://{projectId}-{containerId}-code-{serviceId}.{node}.containers.hoody.icu
```

**Example:**
```
https://proj123-cont456-code-svc789.us-east-1.containers.hoody.icu
```

> **Note:** Replace `{projectId}`, `{containerId}`, `{serviceId}`, and `{node}` with actual values from your Hoody deployment. See core SKILL.md for container creation and service discovery.

---

## Common Workflows

### 1. Access VS Code Web Interface

Open the main IDE interface in a browser or verify accessibility:

```
# Check if VS Code interface is accessible
curl -s "https://{BASE_URL}/api/v1/code" -o /dev/null -w "%{http_code}"
```

**Expected:** `200` (authenticated) or `302` redirect to login (if auth enabled).

---

### 2. Authentication Flow

#### Get Login Page

```
# Retrieve login page HTML
curl -s "https://{BASE_URL}/api/v1/code/login"
```

**Expected Response:** HTML login form (when authentication is set to 'password').

#### Authenticate with Password

```
# Login with password (rate limited: 2 attempts/min, 12 attempts/hour)
curl -s -X POST "https://{BASE_URL}/api/v1/code/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "password=your-password" \
  -c cookies.txt
```

**Expected:** Session cookie set, redirect to target page.

#### Logout

```
# Clear session and logout
curl -s "https://{BASE_URL}/api/v1/code/logout" \
  -b cookies.txt
```

**Expected:** Session cookie cleared, redirect to home.

---

### 3. Health Check

```
# Check service health (does NOT count toward heartbeat activity)
curl -s "https://{BASE_URL}/api/v1/code/health"
```

**Expected Response:**
```
{
  "status": "ok",
  "process": {
    "pid": 1234,
    "uptime": 3600
  }
}
```

---

### 4. Extension Management

#### List Installed Extensions

```
# Get all installed extensions
curl -s "https://{BASE_URL}/api/v1/code/extensions/list"
```

**Expected Response:**
```
{
  "extensions": [
    {
      "id": "ms-python.python",
      "version": "2024.1.0"
    }
  ]
}
```

#### Install Extension from VSIX URL

```
# Install extension from HTTPS URL
curl -s -X POST "https://{BASE_URL}/api/v1/code/extensions/install" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/extensions/ms-python-python-2024.1.0.vsix"
  }'
```

**Expected Response:**
```
{
  "status": "installed",
  "extensionId": "ms-python.python"
}
```

**Use Cases:**
- Automated deployment workflows
- Custom extension distribution
- CI/CD pipeline integration

---

### 5. Proxy Local Applications

#### Proxy with Path Stripping

Forward requests to local ports, stripping the proxy prefix:

```
# Proxy to port 3000, strips /proxy/3000 prefix
curl -s "https://{BASE_URL}/api/v1/code/proxy/{port}/{path}"
```

**Behavior:** Strips `/proxy/{port}` prefix; forwards to `http://localhost:{port}/{path}`

#### Proxy with Absolute Path

Forward requests preserving the full path:

```
# Proxy to port 8080, keeps full path
curl -s "https://{BASE_URL}/api/v1/code/absproxy/{port}/{path}"
```

**Behavior:** Keeps full path; forwards to `http://localhost:{port}/{path}`

**Port Range:** 1024–65535

---

### 6. PWA Manifest

```
# Get Progressive Web App manifest
curl -s "https://{BASE_URL}/api/v1/code/manifest.json"
```

**Expected Response:**
```
{
  "name": "Hoody Code",
  "short_name": "Hoody Code",
  "display": "fullscreen",
  "icons": [
    {
      "src": "/_static/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}
```

---

### 7. Encryption Key Management

```
# Generate or retrieve server's web key half (256-bit, stored in user-data-dir)
curl -s -X POST "https://{BASE_URL}/api/v1/code/mint-key"
```

**Expected Response:**
```
{
  "key": "base64-encoded-32-byte-key"
}
```

**Note:** Key is created once and reused across restarts.

---

### 8. Update Check

```
# Check for available Hoody Code updates
curl -s "https://{BASE_URL}/api/v1/code/update/check"
```

**Behavior:** Queries GitHub releases API (unless disabled with `--disable-update-check`). Checks every 6 hours, notifies once per week.

---

### 9. Static Assets and Injected Scripts

#### Serve Static Files

```
# Get static file from build directory
curl -s "https://{BASE_URL}/_static/icon-192.png" -o icon.png
```

**Caching:** Long cache headers in production (based on git commit).

#### Get Injected Scripts

```
# Retrieve injected JavaScript (loaded when --hoody-code flag enabled)
curl -s "https://{BASE_URL}/hoody-code/injected/custom.js"
```

**Behavior:** Scripts loaded sequentially after window load, applied to all views.

---

### 10. Security and Robots

```
# Get security disclosure policy
curl -s "https://{BASE_URL}/security.txt"


# Get robots.txt
curl -s "https://{BASE_URL}/robots.txt"
```

---

## Advanced Operations

### Multi-Step: Automated Extension Deployment

Deploy extensions to a fresh instance with verification:

```
BASE_URL="https://proj123-cont456-code-svc789.us-east-1.containers.hoody.icu"

# Step 1: Verify service is healthy
HEALTH=$(curl -s "$BASE_URL/api/v1/code/health")
echo "$HEALTH" | grep -q '"status":"ok"' || { echo "Service unhealthy"; exit 1; }

# Step 2: Install Python extension
curl -s -X POST "$BASE_URL/api/v1/code/extensions/install" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/extensions/ms-python-python-2024.1.0.vsix"}'

# Step 3: Install Prettier extension
curl -s -X POST "$BASE_URL/api/v1/code/extensions/install" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/extensions/esbenp-prettier-vscode-10.1.0.vsix"}'

# Step 4: Verify installations
curl -s "$BASE_URL/api/v1/code/extensions/list"
```

---

### Multi-Step: Authenticated Workflow

Complete authentication flow with session persistence:

```
BASE_URL="https://proj123-cont456-code-svc789.us-east-1.containers.hoody.icu"
COOKIES="hoody-code-cookies.txt"

# Step 1: Attempt access (expect redirect if auth required)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/api/v1/code")
if [ "$HTTP_CODE" = "302" ]; then
  echo "Authentication required"
fi

# Step 2: Login
curl -s -X POST "$BASE_URL/api/v1/code/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "password=your-secure-password" \
  -c "$COOKIES"

# Step 3: Access with session
curl -s "$BASE_URL/api/v1/code" -b "$COOKIES" -o /dev/null -w "%{http_code}"

# Step 4: Perform authenticated operations
curl -s "$BASE_URL/api/v1/code/extensions/list" -b "$COOKIES"

# Step 5: Logout when done
curl -s "$BASE_URL/api/v1/code/logout" -b "$COOKIES"
rm -f "$COOKIES"
```

---

### Error Recovery: Rate Limit Handling

Handle authentication rate limits gracefully:

```
MAX_ATTEMPTS=2
ATTEMPT=0

while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
  RESPONSE=$(curl -s -X POST "$BASE_URL/api/v1/code/login" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "password=$PASSWORD" \
    -c cookies.txt \
    -w "\n%{http_code}")
  
  HTTP_CODE=$(echo "$RESPONSE" | tail -1)
  BODY=$(echo "$RESPONSE" | head -n -1)
  
  if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
    echo "Login successful"
    break
  elif echo "$BODY" | grep -q "rate limit"; then
    echo "Rate limited. Waiting 60 seconds..."
    sleep 60
    ATTEMPT=$((ATTEMPT + 1))
  else
    echo "Login failed: $BODY"
    exit 1
  fi
done
```

---

### Performance: Proxy Configuration for Development

Set up proxying for a local development stack:

```
BASE_URL="https://proj123-cont456-code-svc789.us-east-1.containers.hoody.icu"

# Frontend dev server on port 3000 (path stripping)
# Access via: /proxy/3000/ -> http://localhost:3000/
curl -s "$BASE_URL/api/v1/code/proxy/3000/"

# API server on port 8080 (absolute path)
# Access via: /absproxy/8080/api/v1/users -> http://localhost:8080/api/v1/users
curl -s "$BASE_URL/api/v1/code/absproxy/8080/api/v1/users"

# WebSocket server on port 9090
# Access via: /absproxy/9090/ws -> http://localhost:9090/ws
curl -s "$BASE_URL/api/v1/code/absproxy/9090/ws"
```

**Port Selection Tips:**
- Use `/proxy/{port}/` for frontend apps (clean URLs)
- Use `/absproxy/{port}/` for APIs (preserve full paths)
- Port range: 1024–65535

---

### State Verification Pattern

Verify service state between operations:

```
BASE_URL="https://proj123-cont456-code-svc789.us-east-1.containers.hoody.icu"

# Function to verify health
verify_health() {
  local status=$(curl -s "$BASE_URL/api/v1/code/health" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
  if [ "$status" != "ok" ]; then
    echo "Service unhealthy: $status"
    return 1
  fi
  return 0
}

# Function to verify extension installed
verify_extension() {
  local ext_id=$1
  curl -s "$BASE_URL/api/v1/code/extensions/list" | grep -q "\"id\":\"$ext_id\""
  return $?
}

# Usage
verify_health || exit 1
curl -s -X POST "$BASE_URL/api/v1/code/extensions/install" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/extension.vsix"}'
verify_extension "my-extension" && echo "Extension installed successfully"
```

---

## Quick Reference

### Essential Endpoints

| Method | Path | Purpose |
|--------|------|---------|
| GET | `/api/v1/code` | Main VS Code interface |
| GET | `/api/v1/code/health` | Health check (no heartbeat impact) |
| GET | `/api/v1/code/login` | Login page |
| POST | `/api/v1/code/login` | Authenticate |
| GET | `/api/v1/code/logout` | Clear session |
| POST | `/api/v1/code/extensions/install` | Install extension |
| GET | `/api/v1/code/extensions/list` | List extensions |
| GET | `/api/v1/code/proxy/{port}/{path}` | Proxy (strip prefix) |
| GET | `/api/v1/code/absproxy/{port}/{path}` | Proxy (keep path) |
| POST | `/api/v1/code/mint-key` | Generate encryption key |
| GET | `/api/v1/code/manifest.json` | PWA manifest |
| GET | `/api/v1/code/update/check` | Check for updates |
| GET | `/_static/{path}` | Static files |
| GET | `/hoody-code/injected/{script}` | Injected scripts |
| GET | `/security.txt` | Security policy |
| GET | `/robots.txt` | Robots file |

### Key Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `port` | integer (1024-65535) | Local port for proxy endpoints |
| `path` | string | File path or route path |
| `url` | string (HTTPS) | VSIX download URL for extension install |
| `password` | string | Authentication password |

### Response Patterns

**Health Check:**
```
{
  "status": "ok",
  "process": {
    "pid": 1234,
    "uptime": 3600
  }
}
```

**Extension List:**
```
{
  "extensions": [
    {
      "id": "publisher.name",
      "version": "1.0.0"
    }
  ]
}
```

**Extension Install:**
```
{
  "status": "installed",
  "extensionId": "publisher.name"
}
```

### Authentication Notes

- Session-based via cookies
- Rate limit: 2 attempts/minute, 12 attempts/hour
- Password hashed with argon2 (if `--hashed-password` used)
- Redirects to `/login` when unauthenticated

### Proxy Behavior

| Endpoint | Path Handling | Use Case |
|----------|---------------|----------|
| `/proxy/{port}/{path}` | Strips `/proxy/{port}` prefix | Frontend apps |
| `/absproxy/{port}/{path}` | Keeps full path | APIs, WebSocket |

### Caching

- Static files: Long cache headers in production (git commit-based)
- Injected scripts: No caching