Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add rules/pauljphilp/effectpatterns/merge-multiple-streamsgit clone --depth 1 https://github.com/PaulJPhilp/EffectPatternsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/rules/pauljphilp/effectpatterns/merge-multiple-streams)<a href="https://agentmods.dev/rules/pauljphilp/effectpatterns/merge-multiple-streams"><img src="https://agentmods.dev/badge/rules/pauljphilp/effectpatterns/merge-multiple-streams.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.01393 | $0.01393 |
| Opus 5 | $0.00696 | $0.00696 |
| Sonnet 5 | $0.00279 | $0.00279 |
| Haiku 4.5 | $0.00139 | $0.00139 |
Grade A, and why
merge-multiple-streams scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 195 lines — stays where its author put it; the contents beside it link to each section on GitHub.
description: Use merge, concat, or zip to combine multiple streams based on your requirements. globs: "**/*.ts" alwaysApply: true
Merge Multiple Streams
Rule: Use merge, concat, or zip to combine multiple streams based on your requirements.
Example
import { Effect, Stream, Duration, Chunk } from "effect"
// ============================================
// 1. Merge - interleave as items arrive
// ============================================
const mergeExample = Effect.gen(function* () {
// Two streams producing at different rates
const fast = Stream.fromIterable(["A1", "A2", "A3"]).pipe(
Stream.tap(() => Effect.sleep("100 millis"))
)
const slow = Stream.fromIterable(["B1", "B2", "B3"]).pipe(
Stream.tap(() => Effect.sleep("200 millis"))
)
// Merge interleaves based on arrival time
const merged = Stream.merge(fast, slow)
yield* merged.pipe(
Stream.tap((item) => Effect.log(`Received: ${item}`)),
Stream.runDrain
)
// Output order depends on timing: A1, B1, A2, A3, B2, B3 (approximately)
})
// ============================================
// 2. Merge all - combine many streams
// ============================================
const mergeAllExample = Effect.gen(function* () {
const streams = [
Stream.fromIterable([1, 2, 3]),
Stream.fromIterable([10, 20, 30]),
Stream.fromIterable([100, 200, 300]),
]
const merged = Stream.mergeAll(streams, { concurrency: 3 })
const results = yield* merged.pipe(Stream.runCollect)
yield* Effect.log(`Merged: ${Chunk.toReadonlyArray(results)}`)
})
// ============================================
// 3. Concat - sequence streams
// ============================================
const concatExample = Effect.gen(function* () {
const first = Stream.fromIterable([1, 2, 3])
const second = Stream.fromIterable([4, 5, 6])
const third = Stream.fromIterable([7, 8, 9])
// Concat waits for each stream to complete
const sequential = Stream.concat(Stream.concat(first, second), third)
const results = yield* sequential.pipe(Stream.runCollect)
yield* Effect.log(`Concatenated: ${Chunk.toReadonlyArray(results)}`)
// Always: [1, 2, 3, 4, 5, 6, 7, 8, 9]
})
// ============================================
// 4. Zip - pair items from streams
// ============================================
const zipExample = Effect.gen(function* () {
const names = Stream.fromIterable(["Alice", "Bob", "Charlie"])
const ages = Stream.fromIterable([30, 25, 35])
// Zip pairs items by position
const zipped = Stream.zip(names, ages)
yield* zipped.pipe(
Stream.tap(([name, age]) => Effect.log(`${name} is ${age} years old`)),
Stream.runDrain
)
})
// ============================================
// 5. ZipWith - pair and transform
// ============================================
const zipWithExample = Effect.gen(function* () {
const prices = Stream.fromIterable([100, 200, 150])
const quantities = Stream.fromIterable([2, 1, 3])
// Zip and calculate total
const totals = Stream.zipWith(prices, quantities, (price, qty) => ({
price,
quantity: qty,
total: price * qty,
}))
yield* totals.pipe(
Stream.tap((item) => Effect.log(`${item.quantity}x @ $${item.price} = $${item.total}`)),
Stream.runDrain
)
})
// ============================================
// 6. ZipLatest - combine with latest values
// ============================================
const zipLatestExample = Effect.gen(function* () {
// Simulate different update rates
const temperature = Stream.fromIterable([20, 21, 22, 23]).pipe(
Stream.tap(() => Effect.sleep("100 millis"))
)
const humidity = Stream.fromIterable([50, 55, 60]).pipe(
Stream.tap(() => Effect.sleep("150 millis"))
)
// ZipLatest always uses the latest value from each stream
const combined = Stream.zipLatest(temperature, humidity)
yield* combined.pipe(
Stream.tap(([temp, hum]) => Effect.log(`Temp: ${temp}°C, Humidity: ${hum}%`)),
Stream.runDrain
)
})
// ============================================
// 7. Practical example: Merge event sources
// ============================================
interface Event {
source: string
type: string
data: unknown
}
const mergeEventSources = Effect.gen(function* () {
// Simulate multiple event sources
const mouseEvents = Stream.fromIterable([
{ source: "mouse", type: "click", data: { x: 100, y: 200 } },
{ source: "mouse", type: "move", data: { x: 150, y: 250 } },
] as Event[])
const keyboardEvents = Stream.fromIterable([
{ source: "keyboard", type: "keydown", data: { key: "Enter" } },
{ source: "keyboard", type: "keyup", data: { key: "Enter" } },
] as Event[])
const networkEvents = Stream.fromIterable([
{ source: "network", type: "response", data: { status: 200 } },
] as Event[])
// Merge all event sources
const allEvents = Stream.mergeAll([mouseEvents, keyboardEvents, networkEvents])
yield* allEvents.pipe(
Stream.tap((event) =>
Effect.log(`[${event.source}] ${event.type}: ${JSON.stringify(event.data)}`)
),
Stream.runDrain
)
})
// ============================================
// 8. Run examples
// ============================================
const program = Effect.gen(function* () {
yield* Effect.log("=== Merge Example ===")
yield* mergeExample
yield* Effect.log("\n=== Concat Example ===")
yield* concatExample
yield* Effect.log("\n=== Zip Example ===")
yield* zipExample
})
Effect.runPromise(program)
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- yesterday First seen · 195 lines · 1,393 tokens per session scan A 65325210ed69
merge-multiple-streams is a cursor rule published in the GitHub repository PaulJPhilp/EffectPatterns (796 stars, last pushed 2mo ago), licensed MIT. It adds 1,393 tokens to every session, about $0.0070 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-03.
Other cursor rules, from other repositories
typescript-code-generation-rules
Rules for generating TypeScript code in Next.js 14 components, including component definition syntax, props definitions, and named/default exports.
react-and-typescript-general-rules
General rules for React and TypeScript projects, focusing on code clarity and best practices.
typescript-coding-style
Enforces code style and best practices for TypeScript files.
javascript-typescript-code-style
Rules for JavaScript and TypeScript code style, including modern features, functional patterns, and descriptive naming conventions.
code-style-and-improvements
This rule focuses on code style, refactoring suggestions, and leveraging the latest ES and Node.js features for JavaScript, TypeScript, and Python files.
key-conventions
Key coding conventions for Astro projects including style guide and typescript.