Skip to content

Commit 9dc01ed

Browse files
committed
Add context7
1 parent 683117d commit 9dc01ed

File tree

5 files changed

+301
-3
lines changed

5 files changed

+301
-3
lines changed

context7.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "https://context7.com/schema/context7.json",
3+
"projectTitle": "Ox",
4+
"description": "Safe direct-style concurrency and resiliency for Scala on the JVM",
5+
"folders": [
6+
"generated-doc"
7+
],
8+
"rules": [
9+
"Use high-level concurrency operations like par(), race(), and timeout() when possible",
10+
"For manual concurrency, always use structured concurrency with supervised scopes to ensure proper cleanup of threads and resources",
11+
"Keep concurrency scopes as small as possible, creating short-lived scopes for single requests or jobs",
12+
"Use useCloseableInScope() for automatic resource management that ensures cleanup on scope exit",
13+
"Handle errors through either exceptions (for bugs/unexpected situations) or application errors as values using Either",
14+
"Prefer either blocks with .ok() for streamlined Either handling instead of manual pattern matching",
15+
"Use blocking operations freely, instead of using Futures",
16+
"Use Flows for defining asynchronous data processing pipelines",
17+
"Use .buffer() to create explicit asynchronous boundaries in flows when producers and consumers need decoupling",
18+
"Use Flow.usingEmit for custom flow creation but never share FlowEmit instances across threads",
19+
"Use channels for integrating with callback-based and reactive APIs within structured concurrency scopes",
20+
"Leverage retry() with exponential backoff and jitter for resilient error handling of transient failures",
21+
"Use repeat() with appropriate schedules for periodic task execution within supervised scopes",
22+
"Use .pipe, .tap, uninterruptible, .discard, debug utility functions"
23+
]
24+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: false
5+
---
6+
# Ox Utility Functions
7+
8+
Ox provides utility functions for common operations in direct-style code. These are often inline methods with no runtime overhead.
9+
10+
## Top-Level Utilities
11+
12+
```scala
13+
import ox.{sleep, debug, uninterruptible}
14+
import scala.concurrent.duration.*
15+
16+
// Scala-friendly sleep
17+
sleep(2.seconds) // Better than Thread.sleep
18+
19+
// Debug printing with expression and value
20+
debug(computeExpensiveValue()) // Prints: computeExpensiveValue() = 42
21+
22+
// Uninterruptible code blocks
23+
uninterruptible {
24+
criticalCleanupOperation()
25+
updateImportantState()
26+
} // Cannot be interrupted even if thread/fork is cancelled
27+
```
28+
29+
## Extension Methods for Chaining
30+
31+
```scala
32+
// Pipe - apply function and return result (useful for chaining)
33+
val result = getData()
34+
.pipe(processData)
35+
.pipe(validateData)
36+
.pipe(formatData)
37+
38+
// Tap - apply function but return original value (useful for side effects)
39+
val user = fetchUser(userId)
40+
.tap(u => logger.info(s"Fetched user: ${u.name}"))
41+
.tap(auditService.logAccess)
42+
.tap(cacheService.store)
43+
44+
// Discard - avoid "discarded non-unit value" warnings
45+
computeValue().discard // Explicitly discard result
46+
```
47+
48+
## Exception Handling Utilities
49+
50+
```scala
51+
// Handle exceptions with side effects
52+
val result = riskyOperation()
53+
.tapException(e => logger.error(s"Operation failed: ${e.getMessage}"))
54+
.tapNonFatalException(e => metrics.incrementErrorCounter())
55+
```
56+
57+
## Future Integration
58+
59+
```scala
60+
import scala.concurrent.Future
61+
62+
// Block on Future completion (direct-style integration)
63+
val futureResult: Future[String] = asyncOperation()
64+
val result: String = futureResult.get() // Blocks until complete
65+
```
66+
67+
## Real-World Examples
68+
69+
```scala
70+
// Data processing pipeline with utilities
71+
def processUserData(userId: String): ProcessedUser = {
72+
fetchUser(userId)
73+
.tap(u => debug(u)) // Debug log the user
74+
.pipe(enrichUserData)
75+
.tap(cacheService.store) // Cache the enriched data
76+
.pipe(validateUser)
77+
.tapException(e => alertService.sendAlert(s"User processing failed: $e"))
78+
}
79+
80+
// Critical operation that shouldn't be interrupted
81+
def saveToDatabase(data: Data): Unit = uninterruptible {
82+
database.beginTransaction()
83+
database.save(data)
84+
database.commit()
85+
auditLog.record(s"Saved data: ${data.id}")
86+
}
87+
88+
// Working with legacy async code
89+
def integrateLegacyService(): String = {
90+
val futureData = legacyService.fetchDataAsync()
91+
val data = futureData.get() // Convert to direct-style
92+
93+
processData(data)
94+
.tap(result => logger.info(s"Processed: $result"))
95+
.pipe(_.toString)
96+
}
97+
```
98+
99+
## Best Practices
100+
101+
1. **Use `pipe`** for transformation chains
102+
2. **Use `tap`** for side effects that don't change the value
103+
3. **Use `debug`** during development for easy debugging
104+
4. **Use `uninterruptible`** for critical sections that must complete
105+
5. **Use `.discard`** to explicitly ignore return values
106+
6. **Use `.get()`** to integrate Future-based APIs into direct-style code
107+
108+
## Common Patterns
109+
110+
```scala
111+
// Good: Clear data processing pipeline
112+
data
113+
.pipe(validate)
114+
.tap(logValidation)
115+
.pipe(transform)
116+
.tap(cache.store)
117+
.pipe(serialize)
118+
119+
// Good: Critical cleanup with uninterruptible
120+
uninterruptible {
121+
resource.close()
122+
tempFiles.cleanup()
123+
locks.release()
124+
}
125+
126+
// Good: Debug complex expressions
127+
val complexResult = debug {
128+
data.filter(_.isValid)
129+
.map(transform)
130+
.reduce(combine)
131+
} // Shows both expression and result
132+
```
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
description: Ox provides utility functions for common operations in direct-style code: `.pipe`, `.tap`, `.discard`, `uninterruptible` and `debug`. These are often inline methods with no runtime overhead.
3+
globs:
4+
alwaysApply: false
5+
---
6+
# Ox Utility Functions
7+
8+
Ox provides utility functions for common operations in direct-style code: `.pipe`, `.tap`, `.discard`, `uninterruptible` and `debug`. These are often inline methods with no runtime overhead.
9+
10+
## Top-Level Utilities
11+
12+
```scala
13+
import ox.{sleep, debug, uninterruptible}
14+
import scala.concurrent.duration.*
15+
16+
// Scala-friendly sleep
17+
sleep(2.seconds) // Better than Thread.sleep
18+
19+
// Debug printing with expression and value
20+
debug(computeExpensiveValue()) // Prints: computeExpensiveValue() = 42
21+
22+
// Uninterruptible code blocks
23+
uninterruptible {
24+
criticalCleanupOperation()
25+
updateImportantState()
26+
} // Cannot be interrupted even if thread/fork is cancelled
27+
```
28+
29+
## Extension Methods for Chaining
30+
31+
```scala
32+
// Pipe - apply function and return result (useful for chaining)
33+
val result = getData()
34+
.pipe(processData)
35+
.pipe(validateData)
36+
.pipe(formatData)
37+
38+
// Tap - apply function but return original value (useful for side effects)
39+
val user = fetchUser(userId)
40+
.tap(u => logger.info(s"Fetched user: ${u.name}"))
41+
.tap(auditService.logAccess)
42+
.tap(cacheService.store)
43+
44+
// Discard - avoid "discarded non-unit value" warnings
45+
computeValue().discard // Explicitly discard result
46+
```
47+
48+
## Exception Handling Utilities
49+
50+
```scala
51+
// Handle exceptions with side effects
52+
val result = riskyOperation()
53+
.tapException(e => logger.error(s"Operation failed: ${e.getMessage}"))
54+
.tapNonFatalException(e => metrics.incrementErrorCounter())
55+
```
56+
57+
## Future Integration
58+
59+
```scala
60+
import scala.concurrent.Future
61+
62+
// Block on Future completion (direct-style integration)
63+
val futureResult: Future[String] = asyncOperation()
64+
val result: String = futureResult.get() // Blocks until complete
65+
```
66+
67+
## Real-World Examples
68+
69+
```scala
70+
// Data processing pipeline with utilities
71+
def processUserData(userId: String): ProcessedUser = {
72+
fetchUser(userId)
73+
.tap(u => debug(u)) // Debug log the user
74+
.pipe(enrichUserData)
75+
.tap(cacheService.store) // Cache the enriched data
76+
.pipe(validateUser)
77+
.tapException(e => alertService.sendAlert(s"User processing failed: $e"))
78+
}
79+
80+
// Critical operation that shouldn't be interrupted
81+
def saveToDatabase(data: Data): Unit = uninterruptible {
82+
database.beginTransaction()
83+
database.save(data)
84+
database.commit()
85+
auditLog.record(s"Saved data: ${data.id}")
86+
}
87+
88+
// Working with legacy async code
89+
def integrateLegacyService(): String = {
90+
val futureData = legacyService.fetchDataAsync()
91+
val data = futureData.get() // Convert to direct-style
92+
93+
processData(data)
94+
.tap(result => logger.info(s"Processed: $result"))
95+
.pipe(_.toString)
96+
}
97+
```
98+
99+
## Best Practices
100+
101+
1. **Use `pipe`** for transformation chains
102+
2. **Use `tap`** for side effects that don't change the value
103+
3. **Use `debug`** during development for easy debugging
104+
4. **Use `uninterruptible`** for critical sections that must complete
105+
5. **Use `.discard`** to explicitly ignore return values
106+
6. **Use `.get()`** to integrate Future-based APIs into direct-style code
107+
108+
## Common Patterns
109+
110+
```scala
111+
// Good: Clear data processing pipeline
112+
data
113+
.pipe(validate)
114+
.tap(logValidation)
115+
.pipe(transform)
116+
.tap(cache.store)
117+
.pipe(serialize)
118+
119+
// Good: Critical cleanup with uninterruptible
120+
uninterruptible {
121+
resource.close()
122+
tempFiles.cleanup()
123+
locks.release()
124+
}
125+
126+
// Good: Debug complex expressions
127+
val complexResult = debug {
128+
data.filter(_.isValid)
129+
.map(transform)
130+
.reduce(combine)
131+
} // Shows both expression and result
132+
```

cursor-rules/generation/rules-list.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ Use actors for stateful components that need isolation and controlled access, es
9191
### ox-flow-text-processing
9292
Use built-in text transformation operators (`encodeUtf8`, `linesUtf8`, `decodeStringUtf8`) for efficient text processing in flows.
9393

94+
### ox-utility-functions
95+
Ox provides utility functions for common operations in direct-style code: `.pipe`, `.tap`, `.discard`, `uninterruptible` and `debug`. These are often inline methods with no runtime overhead.
96+
9497
## Integration & Interoperability
9598

9699
### ox-reactive-streams

doc/info/ai.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Using Ox with AI tools
22

3-
If you are using AI coding assistants or agents, they will only be as useful, as much they know about Ox. Since Ox's documentation (especially the latest features) might not be in the LLMs trainings set, it might be useful to let the models know about Ox's capabilities and the preferred way that Ox should be used.
3+
If you are using AI coding assistants or agents, they will only be as useful, as much they know about Ox. Since Ox's documentation (especially the latest features) might not be in the LLMs training set, it might be useful to let the models know about Ox's capabilities and the preferred way that Ox should be used.
44

55
Since this is an evolving field, there's no one standard yet, and there are several options to explore. Below you can find a short summary.
66

77
## Cursor documentation indexing
88

9-
If you are using [Cursor](), you might try the [built-in documentation indexing](https://docs.cursor.com/guides/advanced/working-with-documentation) feature. Select `@Docs` -> `Add New Doc` in the editor, or go to `Cursor` -> `Settings` -> `Cursor Settings` -> `Indexing & Docs` -> `Add docs`. In the address field, enter [https://ox.softwaremill.com/latest/](https://ox.softwaremill.com/latest/). After a while, the Ox documentation should be indexed.
9+
If you are using [Cursor](https://www.cursor.com), you might try the [built-in documentation indexing](https://docs.cursor.com/guides/advanced/working-with-documentation) feature. Select `@Docs` -> `Add New Doc` in the editor, or go to `Cursor` -> `Settings` -> `Cursor Settings` -> `Indexing & Docs` -> `Add docs`. In the address field, enter [https://ox.softwaremill.com/latest/](https://ox.softwaremill.com/latest/). After a while, the Ox documentation should be indexed.
1010

1111
Information is scarce on how this actually works, but by analogy with code indexing, this seems to store embeddings of documentation pages on Cursor's servers, which are then used for relevant user queries. Or using AI-terminology, it's a [RAG system](https://cloud.google.com/use-cases/retrieval-augmented-generation?hl=en).
1212

@@ -16,4 +16,11 @@ You can then use `@Docs Ox` to hint to Cursor to use Ox's documentation.
1616

1717
[Rules](https://docs.cursor.com/context/rules) provide guidance to the LLMs, either by adding the content of the rule as context for each request, by having the models request the content of a rule, or by explicitly mentioning it in the prompt.
1818

19-
Rules might be project-scoped or tied to the user. Project rules are stored in a `.cursor/rules` directory. Ox contains a set of rules, which might guide LLMs when working with Ox-based applications. To include them in your project, simply fetch the current rules into your `.cursor/rules/` directory
19+
Rules might be project-scoped or tied to the user. Project rules are stored in a `.cursor/rules` directory. Ox contains a set of rules, which might guide LLMs when working with Ox-based applications. To include them in your project, simply fetch the current rules into your `.cursor/rules/` directory:
20+
21+
```
22+
git clone --depth=1 --filter=blob:none --sparse https://github.com/softwaremill/ox.git && cd ox && git sparse-checkout set doc && mkdir -p ../.cursor/rules && cp -r doc/* ../.cursor/rules && cd .. && rm -rf ox
23+
```
24+
25+
Some of the rules are automatically applied to the context (to let the model know about basic capabilities), some are agent-requested, which exposes only the rule descriptions to the context. If needed, the agent can fetch the entire rule content, to explore a subject in more depth.
26+

0 commit comments

Comments
 (0)