<!--
hoody-watch Subskill (cli)
Auto-generated by Hoody Skills Generator
Generated: 2026-06-19T22:50:22.090Z
Model: mimo-v2.5-pro
Mode: cli


Tokens: 6199

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

# hoody-watch Subskill

## Overview

### Purpose

The `hoody-watch` service provides file system watchers that observe file changes within containers and stream live events. It enables real-time monitoring of filesystem activity using inotify-based subscriptions, supporting use cases like development hot-reload, log tailing, configuration change detection, and automated pipeline triggers.

### When to Use

- **Development workflows**: Monitor source files for changes to trigger rebuilds or hot-reload
- **Log monitoring**: Tail log files for new entries in real-time
- **Configuration tracking**: Detect when config files are modified or created
- **Build pipelines**: Watch for artifact output or dependency changes
- **Security auditing**: Monitor sensitive directories for unauthorized modifications

### Hoody Philosophy Fit

`hoody-watch` follows Hoody's container-first philosophy. Watchers are scoped to individual containers, enabling:

- **Isolation**: Each container's watchers are independent, preventing cross-container noise
- **Reproducibility**: Watch configurations are declarative and can be version-controlled
- **Simplicity**: CLI-first interface eliminates complex setup; watchers "just work"
- **Observability**: Built-in health checks and event streaming without external dependencies

### Architecture

```
┌─────────────────────────────────────────────────────┐
│  hoody CLI                                          │
│    ↓                                                │
│  hoody-watch service                                │
│    ├── Health endpoint (liveness/readiness)         │
│    ├── Watcher CRUD (create/list/get/delete)        │
│    └── Event streaming (SSE / WebSocket)            │
│         ↓                                           │
│  Container filesystem (inotify)                     │
└─────────────────────────────────────────────────────┘
```

---

## Common Workflows

### Workflow 1: Create and Monitor a Watcher

This is the fundamental pattern—create a watcher on a path, then stream its events.

**Step 1: Create a watcher**

```
# Create a watcher on /app/src directory
hoody watch create --paths /app/src -c my-container-id
```

Response:
```
{
  "id": "watch-abc123",
  "paths": ["/app/src"],
  "status": "active",
  "created_at": "2025-11-05T10:00:00Z"
}
```

**Step 2: Verify the watcher exists**

```
# Retrieve watcher details and confirm active status
hoody watch get --id watch-abc123 -c my-container-id
```

Response:
```
{
  "id": "watch-abc123",
  "paths": ["/app/src"],
  "status": "active",
  "events_count": 0,
  "created_at": "2025-11-05T10:00:00Z"
}
```

**Step 3: Stream live events**

```
# Start streaming events in real-time via Server-Sent Events
hoody watch stream --id watch-abc123 -c my-container-id
```

Output (as files change):
```
{
  "event_id": "evt-001",
  "watcher_id": "watch-abc123",
  "path": "/app/src/index.js",
  "kind": "modified",
  "timestamp": "2025-11-05T10:05:23Z"
}
```

---

### Workflow 2: List and Inspect All Watchers

Use this pattern to audit active watchers across a container.

**Step 1: List all watchers**

```
# List all watchers with pagination
hoody watch list -c my-container-id
```

Response:
```
{
  "watchers": [
    {
      "id": "watch-abc123",
      "paths": ["/app/src"],
      "status": "active"
    },
    {
      "id": "watch-def456",
      "paths": ["/var/log/app"],
      "status": "active"
    }
  ],
  "total": 2,
  "page": 1
}
```

**Step 2: Get details for a specific watcher**

```
# Inspect watcher configuration and statistics
hoody watch get --id watch-def456 -c my-container-id
```

Response:
```
{
  "id": "watch-def456",
  "paths": ["/var/log/app"],
  "status": "active",
  "events_count": 142,
  "last_event_at": "2025-11-05T09:58:00Z",
  "created_at": "2025-11-04T14:00:00Z"
}
```

---

### Workflow 3: Create a Filtered Watcher

Create watchers with include/exclude patterns to reduce noise.

**Step 1: Create watcher with filters**

```
# Watch only JavaScript files, exclude node_modules
hoody watch create \
  --paths /app/src \
  --include "*.js" \
  --exclude "*.test.js" \
  --ignore-dirs node_modules \
  -c my-container-id
```

Response:
```
{
  "id": "watch-ghi789",
  "paths": ["/app/src"],
  "filters": {
    "include": ["*.js"],
    "exclude": ["*.test.js"],
    "ignore_dirs": ["node_modules"]
  },
  "status": "active",
  "created_at": "2025-11-05T10:10:00Z"
}
```

**Step 2: Verify filtered events**

```
# Stream events—only matching files will appear
hoody watch stream --id watch-ghi789 -c my-container-id
```

Only changes to `.js` files outside `node_modules` (excluding test files) will emit events.

---

### Workflow 4: Review Historical Events

Retrieve past events for analysis or replay.

**Step 1: List historical events**

```
# Get recent events for a watcher (paged)
hoody watch list-events --id watch-abc123 -c my-container-id
```

Response:
```
{
  "events": [
    {
      "event_id": "evt-003",
      "path": "/app/src/utils.js",
      "kind": "created",
      "timestamp": "2025-11-05T10:12:00Z"
    },
    {
      "event_id": "evt-002",
      "path": "/app/src/index.js",
      "kind": "modified",
      "timestamp": "2025-11-05T10:10:00Z"
    },
    {
      "event_id": "evt-001",
      "path": "/app/src/config.json",
      "kind": "modified",
      "timestamp": "2025-11-05T10:05:23Z"
    }
  ],
  "total": 3,
  "page": 1
}
```

**Step 2: Resume from a known event**

```
# Get events after a specific event ID
hoody watch list-events --id watch-abc123 --since-id evt-002 -c my-container-id
```

Response:
```
{
  "events": [
    {
      "event_id": "evt-003",
      "path": "/app/src/utils.js",
      "kind": "created",
      "timestamp": "2025-11-05T10:12:00Z"
    }
  ],
  "total": 1,
  "page": 1
}
```

---

### Workflow 5: Clean Up a Watcher

Remove watchers that are no longer needed.

**Step 1: Verify watcher state before deletion**

```
# Confirm the watcher exists and check its event count
hoody watch get --id watch-def456 -c my-container-id
```

Response:
```
{
  "id": "watch-def456",
  "paths": ["/var/log/app"],
  "status": "active",
  "events_count": 142,
  "created_at": "2025-11-04T14:00:00Z"
}
```

**Step 2: Delete the watcher**

```
# Delete the watcher and tear down inotify subscriptions
hoody watch delete --id watch-def456 -c my-container-id
```

Response:
```
{
  "id": "watch-def456",
  "status": "deleted"
}
```

**Step 3: Confirm deletion**

```
# Verify the watcher no longer appears
hoody watch list -c my-container-id
```

Response:
```
{
  "watchers": [
    {
      "id": "watch-abc123",
      "paths": ["/app/src"],
      "status": "active"
    }
  ],
  "total": 1,
  "page": 1
}
```

---

### Workflow 6: Health Check

Verify the watch service is operational before creating watchers.

**Step 1: Run health check**

```
# Check liveness, memory usage, and active watcher count
hoody watch health -c my-container-id
```

Response:
```
{
  "status": "healthy",
  "memory_mb": 42,
  "watcher_count": 3,
  "uptime_seconds": 86400
}
```

---

## Advanced Operations

### Multi-Path Watcher Setup

Create watchers monitoring multiple directories simultaneously.

```
# Watch source AND config directories in a single watcher
hoody watch create \
  --paths /app/src \
  --paths /app/config \
  --include "*.js" \
  --include "*.json" \
  --ignore-dirs node_modules \
  --ignore-dirs .git \
  -c my-container-id
```

Response:
```
{
  "id": "watch-multi-001",
  "paths": ["/app/src", "/app/config"],
  "filters": {
    "include": ["*.js", "*.json"],
    "ignore_dirs": ["node_modules", ".git"]
  },
  "status": "active",
  "created_at": "2025-11-05T11:00:00Z"
}
```

### Reconnecting Stream with Resume

When streaming over SSE, use `--since-id` to resume from the last received event after a disconnection.

**Step 1: Note the last event ID during streaming**

```
{
  "event_id": "evt-047",
  "path": "/app/src/app.js",
  "kind": "modified",
  "timestamp": "2025-11-05T12:30:00Z"
}
```

**Step 2: Resume from that event after reconnect**

```
# Resume streaming from event evt-047
hoody watch stream --id watch-abc123 --since-id evt-047 -c my-container-id
```

This ensures no events are missed during transient disconnections.

### Error Recovery: Watcher in Error State

If a watcher enters an error state (e.g., path no longer exists), recover by deleting and recreating.

**Step 1: Detect error state**

```
hoody watch get --id watch-broken-001 -c my-container-id
```

Response:
```
{
  "id": "watch-broken-001",
  "paths": ["/app/removed-dir"],
  "status": "error",
  "error": "path_not_found",
  "events_count": 0,
  "created_at": "2025-11-05T08:00:00Z"
}
```

**Step 2: Delete the broken watcher**

```
hoody watch delete --id watch-broken-001 -c my-container-id
```

**Step 3: Recreate with correct path**

```
hoody watch create --paths /app/src -c my-container-id
```

### Performance Considerations

| Scenario | Recommendation |
|----------|----------------|
| Large directories (10k+ files) | Use `--ignore-dirs` to exclude build artifacts, `node_modules`, `.git` |
| Deep nesting | Use `--include` patterns to limit scope to relevant file types |
| High-frequency changes | Use `--kinds` to filter event types (e.g., only `created`, `deleted`) |
| Multiple watchers | Each watcher consumes inotify watches; check `hoody watch health` for resource usage |
| Long-running streams | Always use `--since-id` for reconnect to avoid duplicate processing |

### Cleanup Script Pattern

Remove all watchers for a container before redeployment:

```
# Get all watcher IDs
hoody watch list -c my-container-id -o json

# Delete each watcher (example IDs from list output)
hoody watch delete --id watch-abc123 -c my-container-id
hoody watch delete --id watch-ghi789 -c my-container-id
hoody watch delete --id watch-multi-001 -c my-container-id
```

---

## Quick Reference

### Essential Commands

| Command | Purpose | Key Flags |
|---------|---------|-----------|
| `hoody watch health` | Service health check | `-c <container-id>` |
| `hoody watch list` | List all watchers | `-c <container-id>`, `-o json` |
| `hoody watch get --id <id>` | Get watcher details | `-c <container-id>` |
| `hoody watch create --paths <path>` | Create watcher | `--paths` (repeatable), `--include`, `--exclude`, `--ignore-dirs`, `--kinds` |
| `hoody watch delete --id <id>` | Delete watcher | `-c <container-id>` |
| `hoody watch list-events --id <id>` | Historical events | `--since-id`, `--since-timestamp` |
| `hoody watch stream --id <id>` | Live event stream (SSE) | `--since-id` for resume |

### Required Parameters

| Command | Required | Optional |
|---------|----------|----------|
| `create` | `--paths` (at least one) | `--include`, `--exclude`, `--ignore-dirs`, `--kinds` |
| `get` | `--id` | — |
| `delete` | `--id` | — |
| `list-events` | `--id` | `--since-id`, `--since-timestamp` |
| `stream` | `--id` | `--since-id` |

### Event Kinds

Events include file system operations:

- `created` — new file appeared
- `modified` — file content changed
- `deleted` — file removed
- `renamed` — file moved or renamed

### Typical Response Structures

**Watcher object:**
```
{
  "id": "watch-abc123",
  "paths": ["/app/src"],
  "status": "active",
  "filters": {
    "include": ["*.js"],
    "exclude": ["*.test.js"],
    "ignore_dirs": ["node_modules"]
  },
  "events_count": 47,
  "last_event_at": "2025-11-05T10:05:23Z",
  "created_at": "2025-11-05T09:00:00Z"
}
```

**Event object:**
```
{
  "event_id": "evt-001",
  "watcher_id": "watch-abc123",
  "path": "/app/src/index.js",
  "kind": "modified",
  "timestamp": "2025-11-05T10:05:23Z"
}
```

### Authentication

All commands require authentication. Use one of:

```
# Login interactively
hoody auth login

# Pass token directly
hoody watch list -c my-container-id --token <your-token>

# Set environment variable
export HOODY_TOKEN=<your-token>
hoody watch list -c my-container-id
```