<!--
hoody-notifications Subskill (sdk)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T20:10:50.294Z
Model: mimo-v2.5-pro + fixer:mimo-v2.5-pro
Mode: sdk


Tokens: 4969

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

# hoody-notifications Subskill

## Overview

The `hoody-notifications` service delivers desktop and device notifications via an HTTP API. It enables applications running in Hoody containers to trigger native desktop notifications on target displays, manage notification lifecycle (dismiss/restore), retrieve notification history, and subscribe to real-time notification streams via WebSocket.

### When to Use This Service

- **Triggering desktop alerts** from backend processes, cron jobs, or event-driven workflows
- **Monitoring system events** by subscribing to a real-time notification stream
- **Managing notification state** by dismissing or restoring previously seen notifications
- **Serving notification icons** referenced in notification payloads
- **Health and metrics monitoring** of the notification subsystem

### How It Fits Into Hoody Philosophy

hoody-notifications follows the Hoody Kit service model: it runs as a containerized service with automatic domain routing, zero DNS configuration, and built-in SSL/TLS termination. It is accessed via the standard Hoody Kit URL pattern:

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

The URL segment for this service is `n` (e.g., `...-n-1.node.containers.hoody.icu`). All endpoints live under the `/api/v1/notifications/` path prefix. Authentication is handled through the Hoody SDK client, which manages tokens and credentials transparently.

### SDK Client Setup

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

// Token-based authentication
const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'TOKEN' })

// Credential-based authentication
const client = await HoodyClient.authenticate('https://api.hoody.icu', {
  username: 'USER',
  password: 'PASS'
})
```

---

## Common Workflows

### Workflow 1: Trigger a Desktop Notification

Send a native desktop notification to a specific display.

```
const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'TOKEN' })

// Trigger a notification on display :0
const result = await client.notifications.notify.trigger({
  display: ':0',
  summary: 'Deployment Complete',
  body: 'Production deploy finished successfully at 14:32 UTC.',
  icon: 'dialog-information'
})

console.log('Notification sent:', result)
```

**Required fields**: `display` (string), `summary` (string). Additional optional fields may be accepted per the API schema — see the Essential Parameters table below or the hoody-notifications OpenAPI spec for all available fields.

### Workflow 2: Retrieve Notifications for a Display

Fetch the notification history for one or more displays.

```
// Single display
const notifications = await client.notifications.list({ display: '0' })

// Multiple displays (comma-separated)
const multiDisplay = await client.notifications.list({ display: '0,1' })

// All displays
const allNotifications = await client.notifications.list({ display: 'all' })
```

The `display` parameter accepts a single ID, a comma-separated list, or `"all"`.

### Workflow 3: Paginated Notification Retrieval

For large notification sets, use the async iterator or bulk collector.

```
// Async iterator — processes one page at a time
const iterator = client.notifications.listIterator('0', { limit: 50 })
for await (const notification of iterator) {
  console.log('Notification:', notification)
}

// Collect all pages into a single array
const allNotifications = await client.notifications.listAll('0', { limit: 100 })
console.log(`Total notifications: ${allNotifications.length}`)
```

### Workflow 4: Dismiss and Restore Notifications

Manage notification visibility by dismissing specific notifications and later restoring them.

```
// Dismiss specific notifications by ID
await client.notifications.dismiss({
  notificationIds: ['notif-abc-123', 'notif-def-456']
})

// Verify: dismissed notifications no longer appear in list
const visible = await client.notifications.list({ display: '0' })
const dismissedStillVisible = visible.filter(
  (n: any) => ['notif-abc-123', 'notif-def-456'].includes(n.id)
)
console.log('Dismissed still visible:', dismissedStillVisible.length) // Should be 0

// Restore all dismissed notifications
await client.notifications.clearDismissed()

// Verify: previously dismissed notifications are visible again
const restored = await client.notifications.list({ display: '0' })
const nowVisible = restored.filter(
  (n: any) => ['notif-abc-123', 'notif-def-456'].includes(n.id)
)
console.log('Restored notifications:', nowVisible.length) // Should be 2
```

### Workflow 5: Real-Time Notification Stream

Subscribe to live notifications via WebSocket for immediate delivery.

```
// Subscribe to notifications on specific displays (displays parameter)
client.notifications.connectStream({ displays: '0,1' })

// Subscribe to all displays
client.notifications.connectStream({ displays: 'all' })
```

The `connectStream` method accepts a single string argument for the `displays` parameter. It establishes a WebSocket connection and accepts a comma-separated display list or `"all"`.

### Workflow 6: Retrieve a Notification Icon

Fetch an icon image by its ID. Icon IDs are derived from notification data (session, ID, timestamp, extension).

```
const iconData = await client.notifications.icons.get({ iconId: 'icon-session-123-timestamp.png' })
```

The `iconId` parameter is required and passed as a path parameter.

---

## Advanced Operations

### Conditional Dismiss by Content

Dismiss notifications matching specific criteria — useful for auto-clearing low-priority alerts while preserving critical ones.

```
// Fetch recent notifications
const notifications = await client.notifications.list({ display: '0' })

// Identify low-priority notifications to auto-dismiss
const lowPriority = notifications.filter(
  (n: any) => n.summary.startsWith('Info:') && !n.dismissed
)

if (lowPriority.length > 0) {
  await client.notifications.dismiss({
    notificationIds: lowPriority.map((n: any) => n.id)
  })
  console.log(`Auto-dismissed ${lowPriority.length} low-priority notifications`)
}
```

### Stream-Based Reactive Workflow

Combine the real-time stream with notification triggering for event-driven architectures.

```
// Listen for stream events and react
client.notifications.connectStream({ displays: 'all' })

// In a separate flow, trigger notifications from system events
async function onSystemEvent(eventType: string, payload: any) {
  await client.notifications.notify.trigger({
    display: ':0',
    summary: `System Event: ${eventType}`,
    body: JSON.stringify(payload)
  })
}
```

### Error Recovery: Retry on Transient Failures

Wrap notification calls in retry logic for resilience.

```
async function notifyWithRetry(
  client: HoodyClient,
  params: { display: string; summary: string; body?: string },
  maxRetries = 3
): Promise<any> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await client.notifications.notify.trigger(params)
    } catch (error) {
      if (attempt === maxRetries) throw error
      console.warn(`Attempt ${attempt} failed, retrying...`)
      await new Promise((resolve) => setTimeout(resolve, 1000 * attempt))
    }
  }
}
```

### Health Check and Metrics Monitoring

Monitor service availability and performance.

```
// Health check — unauthenticated, always returns HTTP 200 when service is up
const health = await client.notifications.health.check()
console.log('Service status:', health)

// Prometheus-compatible metrics
const metrics = await client.notifications.health.getMetrics()
console.log('Metrics:', metrics)
```

---

## Quick Reference

### Endpoints

| Method | Path | SDK Method | Purpose |
|--------|------|------------|---------|
| POST | `/api/v1/notifications/notify` | `client.notifications.notify.trigger()` | Trigger desktop notification |
| GET | `/api/v1/notifications/{display}` | `client.notifications.list()` | Get notifications for display(s) |
| POST | `/api/v1/notifications/dismiss` | `client.notifications.dismiss()` | Dismiss notifications by ID |
| DELETE | `/api/v1/notifications/dismiss` | `client.notifications.clearDismissed()` | Restore dismissed notifications (idempotent — safe to retry) |
| GET | `/api/v1/notifications/stream` | `client.notifications.connectStream()` | WebSocket real-time stream |
| GET | `/api/v1/notifications/icons/{iconId}` | `client.notifications.icons.get()` | Fetch notification icon |
| GET | `/api/v1/notifications/health` | `client.notifications.health.check()` | Service health check |
| GET | `/api/v1/notifications/metrics` | `client.notifications.health.getMetrics()` | Prometheus metrics |

### Essential Parameters

| Parameter | Type | Used In | Description |
|-----------|------|---------|-------------|
| `display` | string | notify, list, stream | Target display ID. `notify` uses colon-prefixed format (e.g., `:0`); `list` and `stream` accept bare IDs (e.g., `0`), comma-separated lists, or `"all"` |
| `summary` | string | notify | Notification title (required) |
| `notificationIds` | string[] | dismiss | Array of notification IDs to dismiss |
| `displays` | string | stream | Comma-separated display list or `"all"` |
| `iconId` | string | icons.get | Icon identifier derived from notification data |
| `limit` | integer | list | Max notifications per page |
| `since` | integer | list | Filter notifications after this timestamp |

### Typical Response Formats

**Health check response**: Returns a 9-field standardized JSON object — see `client.notifications.health.check()` in the Health Check and Metrics Monitoring section above for the full schema.

**Notification object** (from list/stream):

```
{
  "id": "notif-abc-123",
  "display": "0",
  "summary": "Deployment Complete",
  "body": "Production deploy finished successfully.",
  "timestamp": 1705312320,
  "session": "session-xyz",
  "dismissed": false
}
```