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


Tokens: 6127

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

# hoody-pipe Subskill

## Overview

**Hoody Pipe** is a real-time, zero-storage data streaming service that enables direct sender-to-receiver communication through named pipe paths. Unlike traditional file storage or message queues, Pipe streams data directly between connected parties with no server-side persistence — when a sender POSTs data to a path, it is immediately forwarded to any receiver(s) listening on that same path.

### When to Use Hoody Pipe

- **File transfers** between agents, containers, or browser clients
- **Real-time data streaming** where latency matters more than durability
- **One-shot data delivery** — send a file, receive acknowledgment, done
- **Cross-origin browser uploads** via the built-in web UI or noscript form
- **Agent-to-agent communication** within or across Hoody projects

### How It Fits Hoody Philosophy

Pipe embodies Hoody's "zero-config, instant utility" philosophy. There are no queues to provision, no topics to create, no storage buckets to manage. You pick a path name, one side sends, the other receives. The service handles connection brokering, CORS, and streaming automatically. Authentication is inherited from the Hoody Proxy layer — no service-level credentials needed.

### Key Characteristics

| Property | Value |
|---|---|
| Storage | None — pure streaming |
| Protocol | HTTP long-poll (receiver blocks until sender connects) |
| Auth | Inherited from Hoody Proxy |
| CORS | Built-in preflight support |
| Transfer modes | POST, PUT (alias for `curl -T` compatibility) |
| Web UI | Built-in HTML interface at root path |

### Base URL Pattern

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

All paths below are relative to this base URL. Do **not** prepend `/api/v1` — it is already included in the path definitions.

---

## Common Workflows

### Workflow 1: Health Check

Verify the pipe service is running and responsive before performing operations.

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'YOUR_TOKEN'
})

const health = await client.pipe.health.check()
console.log(health)
```

Expected response:

```
{
  "status": "healthy",
  "service": "hoody-pipe",
  "version": "1.0.0",
  "uptime": 3600,
  "timestamp": "2025-01-15T10:30:00Z",
  "node": "us-east-1",
  "projectId": "abc123def456",
  "containerId": "cnt789"
}
```

**Verification**: If `status` is not `"healthy"`, do not proceed with pipe operations.

---

### Workflow 2: Get Usage Help

Retrieve built-in help text with curl examples. The help text includes the server's own URL so examples are immediately runnable.

```
const help = await client.pipe.info.getHelp()
console.log(help)
```

Returns plain text with usage instructions. Useful for debugging or when onboarding new agents to the service.

---

### Workflow 3: Send Data to a Pipe Path

Send data to a named path. The request blocks until a receiver connects, then streams the data directly.

```
const response = await client.pipe.send({ path: 'my-data-channel' })
```

**Lifecycle:**
1. Sender calls `send('my-data-channel')` — connection holds open
2. Receiver calls `receive('my-data-channel')` — triggers streaming
3. Data flows directly from sender to receiver
4. Both connections close when transfer completes

**Verification**: A successful send returns after the receiver has consumed the data. If no receiver connects within the timeout window, the sender connection closes with an error.

---

### Workflow 4: Receive Data from a Pipe Path

Block until a sender connects to the specified path, then receive the streamed data.

```
const data = await client.pipe.receive({ path: 'my-data-channel' })
```

**With optional parameters:**

```
const data = await client.pipe.receive('my-data-channel', {
  n: 1,
  download: 'true',
  filename: 'output.txt'
})
```

| Parameter | Type | Description |
|---|---|---|
| `n` | integer | Number of senders to receive from before closing |
| `download` | string | Set to `"true"` to trigger browser download |
| `filename` | string | Suggested filename when `download` is enabled |
| `video` | string | Video-specific streaming options |
| `progress` | string | Enable progress reporting |

---

### Workflow 5: Transfer a File Between Two Agents

Complete file transfer pattern using two coordinated agents.

**Agent A (Sender):**

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'SENDER_TOKEN'
})

// Send file contents to pipe path
// The request will hold until a receiver connects
const result = await client.pipe.send({ path: 'file-transfer-001' })
```

**Agent B (Receiver):**

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'RECEIVER_TOKEN'
})

// Connect to the same path to receive the file
// Blocks until sender is available
const fileData = await client.pipe.receive('file-transfer-001', {
  download: 'true',
  filename: 'report.csv'
})
```

**Coordination tip**: Use a shared naming convention (e.g., `{taskId}-{step}`) so senders and receivers can agree on path names without out-of-band communication.

---

### Workflow 6: Browser-Based Upload via Web UI

Direct a user to the Pipe web interface for manual file or text uploads.

```
const uiPage = await client.pipe.ui.getIndex()
```

Returns an HTML page that allows sending files or text to any pipe path directly from the browser. Also accessible at the root URL (`/`).

---

### Workflow 7: No-JavaScript Upload Form

For restricted environments where JavaScript is disabled, use the noscript endpoint.

```
const form = await client.pipe.ui.getNoScript('my-path', 'file')
```

Returns a pure HTML `<form>` with standard file upload. The `path` query parameter controls which pipe path the form targets.

---

### Workflow 8: CORS Preflight for Cross-Origin Access

When a browser client needs to send data cross-origin, handle the preflight request.

```
const corsHeaders = await client.pipe.corsPreflight({ path: 'my-path' })
```

Returns permissive CORS headers reflecting the request's `Origin`:

```
{
  "Access-Control-Allow-Origin": "https://your-app.example.com",
  "Access-Control-Allow-Methods": "GET, POST, PUT, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization"
}
```

**Note**: The browser handles OPTIONS preflight automatically. You only need this if building custom CORS logic.

---

## Advanced Operations

### Multi-Step Workflow: Bidirectional Agent Communication

Establish a two-way communication channel between agents using two pipe paths.

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'AGENT_TOKEN'
})

// Agent sends a request on one path
async function sendRequest(taskId: string, payload: string) {
  return client.pipe.send(`task-${taskId}-request`)
}

// Agent receives a response on a different path
async function receiveResponse(taskId: string) {
  return client.pipe.receive(`task-${taskId}-response`)
}

// Full round-trip
const taskId = 'abc-123'
await sendRequest(taskId, 'process this data')
const result = await receiveResponse(taskId)
```

**Pattern**: Use `{taskId}-request` and `{taskId}-response` paths to keep channels isolated per task.

---

### Error Recovery: Sender Timeout Handling

If no receiver connects, the sender's long-poll connection will eventually time out. Implement retry logic.

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'TOKEN'
})

async function sendWithRetry(
  path: string,
  maxRetries: number = 3,
  delayMs: number = 5000
): Promise<any> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await client.pipe.send(path)
    } catch (error: any) {
      if (attempt === maxRetries) throw error
      console.warn(`Send attempt ${attempt} failed, retrying in ${delayMs}ms...`)
      await new Promise(resolve => setTimeout(resolve, delayMs))
    }
  }
}
```

---

### Error Recovery: Receiver Timeout Handling

Receivers block waiting for a sender. If the sender never arrives, handle the timeout gracefully.

```
async function receiveWithTimeout(
  path: string,
  timeoutMs: number = 30000
): Promise<any> {
  return Promise.race([
    client.pipe.receive(path),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Receive timeout — no sender connected')), timeoutMs)
    )
  ])
}
```

---

### Performance Considerations

1. **Path naming**: Use descriptive, unique path names to avoid collisions between concurrent operations. Example: `{workflowId}-{step}-{timestamp}`.

2. **Connection holding**: Both `send()` and `receive()` hold HTTP connections open. Avoid creating many concurrent pipe connections from a single agent — they consume server resources.

3. **No buffering**: Pipe has zero server-side storage. If the receiver is not ready when the sender connects, the sender blocks. Coordinate timing or use retry patterns.

4. **Single receiver per transfer**: Each `send()` connects to one `receive()`. For broadcast scenarios, the sender must call `send()` multiple times or use a coordination layer.

5. **Large files**: Pipe streams data — it does not load entire files into memory. Large transfers work naturally, but long-held connections may be subject to proxy timeouts. For very large files, consider chunking across multiple pipe paths.

---

### Workflow: Automated File Pipeline

Chain multiple pipe operations into a processing pipeline.

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

const client = new HoodyClient({
  baseURL: 'https://{projectId}-{containerId}-pipe-{serviceId}.{node}.containers.hoody.icu',
  token: 'TOKEN'
})

async function runPipeline(inputPath: string, outputPath: string) {
  // Step 1: Receive raw data from input pipe
  const rawData = await client.pipe.receive(inputPath)

  // Step 2: Process (example — your actual logic here)
  const processed = transformData(rawData)

  // Step 3: Send processed data to output pipe
  await client.pipe.send(outputPath)

  return processed
}
```

---

## Quick Reference

### Endpoints

| Method | Path | SDK Method | Description |
|---|---|---|---|
| GET | `/api/v1/pipe` | `client.pipe.ui.getIndex()` | Web UI for browser uploads |
| GET | `/api/v1/pipe/noscript` | `client.pipe.ui.getNoScript()` | No-JS upload form |
| GET | `/api/v1/pipe/help` | `client.pipe.info.getHelp()` | Usage help with examples |
| GET | `/api/v1/pipe/health` | `client.pipe.health.check()` | Health check (unauthenticated) |
| GET | `/api/v1/pipe/{path}` | `client.pipe.receive(path)` | Receive data (blocks until sender) |
| POST | `/api/v1/pipe/{path}` | `client.pipe.send(path)` | Send data (blocks until receiver) |
| PUT | `/api/v1/pipe/{path}` | `client.pipe.send(path)` | Send data (PUT alias for curl -T) |
| OPTIONS | `/api/v1/pipe/{path}` | `client.pipe.corsPreflight(path)` | CORS preflight |

### Essential Parameters

| Parameter | Used By | Type | Description |
|---|---|---|---|
| `path` | receive, send, corsPreflight | string (required) | Pipe path name for routing |
| `n` | receive, send | integer | Number of transfers |
| `download` | receive | string | Trigger browser download |
| `filename` | receive | string | Suggested download filename |

### SDK Import

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

### Health Response Format

```
{
  "status": "healthy",
  "service": "hoody-pipe",
  "version": "1.0.0",
  "uptime": 3600,
  "timestamp": "2025-01-15T10:30:00Z",
  "node": "us-east-1",
  "projectId": "abc123def456",
  "containerId": "cnt789"
}
```

### Key Behaviors

- **No storage**: Data streams directly sender → receiver
- **Blocking**: Both send and receive hold connections until paired
- **Health endpoint**: Only at `/api/v1/pipe/health` — bare `/health` returns 404
- **Root alias**: `/` serves the same web UI as `/api/v1/pipe`