eio
Eio concurrency patterns for OCaml applications. Use when Claude needs to: (1) Write concurrent OCaml code with Eio, (2) Handle network operations with cohttp-eio, (3) Manage resource lifecycles with switches, (4) Implement rate limiting or synchronization, (5) Create parallel operations with fibers, (6) Test async code with Eio_mock, (7) Integrate with bytesrw for streaming, or any other Eio-based concurrency tasks
What this skill does
# Eio Concurrency
## Core Concepts
### Why Eio
Eio is an effects-based IO library for OCaml 5. Advantages over Lwt/Async:
- **Direct-style code**: No monads, concurrent code looks like sequential code
- **Performance**: Real stacks, no heap allocations to simulate continuations
- **Better backtraces**: Exceptions show proper call traces
- **Platform optimization**: Generic API with optimized backends (Linux io_uring, POSIX, Windows)
### Capability-Based Design
Pass capabilities explicitly instead of using global resources:
```ocaml
type t = {
net : _ Eio.Net.t;
clock : _ Eio.Time.clock;
fs : _ Eio.Path.t;
}
(* Function signature reveals what resources it needs *)
val connect : net:_ Eio.Net.t -> host:string -> connection
```
**Do**: Pass `net`, `clock`, `fs` explicitly—makes dependencies clear and testable.
**Don't**: Use global modules like `Unix.gettimeofday` or access ambient resources.
### Structured Concurrency with Switches
`Eio.Switch.run` manages resource and fiber lifecycles:
```ocaml
Eio.Switch.run @@ fun sw ->
let conn = connect ~sw server in
(* conn automatically closed when sw exits *)
process conn
```
**Do**: Create switches in the smallest possible scope.
**Don't**: Take a switch argument if you could create one internally.
### Fibers
Lightweight concurrent units running on a single core:
```ocaml
(* Run two operations concurrently *)
Eio.Fiber.both
(fun () -> download file1)
(fun () -> download file2)
(* Only one fiber executes at a time until one performs an effect *)
```
### Cancellation
Cancellation contexts form a tree. Uncaught exceptions propagate upward, cancelling siblings:
```ocaml
(* If one branch fails, the other gets Cancelled *)
Eio.Fiber.both
(fun () -> may_fail ())
(fun () -> other_work ()) (* receives Cancelled if may_fail raises *)
```
Use `Cancel.protect` for operations that must complete:
```ocaml
Eio.Cancel.protect @@ fun () ->
(* This won't be cancelled even if parent is *)
flush_and_close connection
```
## Common Patterns
### Concurrent Operations
```ocaml
(* Parallel map *)
let fetch_all_items api item_ids =
Eio.Fiber.List.map (fun id -> Api.item_info api id) item_ids
(* Race with timeout *)
let with_timeout ~clock duration fn =
Eio.Fiber.first
(fun () -> Eio.Time.sleep clock duration; Error `Timeout)
(fun () -> Ok (fn ()))
(* Fork background task attached to switch *)
Eio.Fiber.fork ~sw (fun () -> background_work ())
```
### File Operations
```ocaml
let ( / ) = Eio.Path.( / )
(* Read file *)
let content = Eio.Path.load (fs / "config.json")
(* Write file with permissions *)
Eio.Path.save ~create:(`Or_truncate 0o600) (fs / "data.bin") content
(* Create directory if needed *)
Eio.Path.mkdirs ~exists_ok:true ~perm:0o755 (fs / "cache")
(* Clean up directory tree *)
Eio.Path.rmtree (fs / "tmp")
(* Check file type *)
match Eio.Path.kind ~follow:true path with
| `Directory -> ...
| `Regular_file -> ...
| `Not_found -> ...
```
### Network Operations
```ocaml
(* TCP client *)
Eio.Net.connect ~sw net (`Tcp (addr, port))
(* TCP server *)
Eio.Net.run_server sock ~on_error:log_error
~max_connections:100
(fun ~sw flow addr -> handle_client ~sw flow)
```
### HTTPS with cohttp-eio
```ocaml
let https_handler uri raw_flow =
let tls_config = create_tls_config () in
let host = Uri.host uri |> Option.map Domain_name.(host_exn % of_string_exn) in
Tls_eio.client_of_flow ?host tls_config raw_flow
let client = Cohttp_eio.Client.make net ~https:(Some https_handler)
```
### Buffered Reading
Always use `max_size` to prevent memory exhaustion:
```ocaml
let body = Eio.Buf_read.(of_flow ~max_size:10_000_000 flow |> take_all)
```
### Synchronization Primitives
**Mutex**:
```ocaml
let mutex = Eio.Mutex.create ()
Eio.Mutex.use_rw mutex (fun () -> shared_state := new_value)
```
**Semaphore for rate limiting**:
```ocaml
let limiter = Eio.Semaphore.make 10
let with_rate_limit fn =
Eio.Semaphore.acquire limiter;
Fun.protect ~finally:(fun () -> Eio.Semaphore.release limiter) fn
```
**Stream for producer/consumer**:
```ocaml
let queue = Eio.Stream.create 100
Eio.Stream.add queue item (* producer *)
let item = Eio.Stream.take queue (* consumer, blocks if empty *)
```
**Condition variables** (must check in loop):
```ocaml
let cond = Eio.Condition.create ()
let mutex = Eio.Mutex.create ()
(* Waiter - MUST use while loop *)
Eio.Mutex.use_rw ~protect:false mutex (fun () ->
while not (check_condition ()) do
Eio.Condition.await cond mutex
done)
(* Signaler *)
Eio.Condition.broadcast cond
```
## Integration with bytesrw
Bridge Eio flows to bytesrw for streaming binary parsing:
```ocaml
(* Eio flow → bytesrw reader *)
let reader_of_flow ?(buf_len = 4096) flow =
let cs = Cstruct.create buf_len in
let read () =
match Eio.Flow.single_read flow cs with
| 0 -> Bytesrw.Bytes.Slice.eod
| n ->
let buf = Cstruct.to_bytes (Cstruct.sub cs 0 n) in
Bytesrw.Bytes.Slice.make buf ~first:0 ~length:n
| exception End_of_file -> Bytesrw.Bytes.Slice.eod
in
Bytesrw.Bytes.Reader.make read
(* Then use with Binary.Reader *)
let r = Binary.Reader.of_reader (reader_of_flow flow)
let frame = Tc_frame.parse r (* effects propagate through *)
```
Note: This involves a copy from Cstruct (Bigarray) to bytes (heap). Unavoidable until OCaml has non-moving bytes.
## RNG Initialization
**Critical for crypto**: Initialize RNG before any crypto operations.
```ocaml
(* For Eio applications *)
Eio_main.run @@ fun env ->
Mirage_crypto_rng_eio.run (module Mirage_crypto_rng.Fortuna) env @@ fun () ->
(* RNG now available *)
let iv = Mirage_crypto_rng.generate 12 in
...
(* For Unix applications (simpler but less integrated) *)
Mirage_crypto_rng_unix.initialize (module Mirage_crypto_rng.Fortuna)
```
Failure to initialize results in predictable random numbers, breaking crypto security.
## Error Handling
Errors use `Eio.Io (err, context)` with nested error codes:
```ocaml
try
Eio.Net.connect ~sw net addr
with
| Eio.Io (Eio.Net.E (Connection_failure _), _) ->
(* Specific error *)
Error `Connection_failed
| Eio.Io (Eio.Net.E _, _) ->
(* Any network error *)
Error `Network_error
| Eio.Io _ ->
(* Any Eio error *)
Error `Io_error
```
Add context when re-raising:
```ocaml
Eio.Exn.reraise_with_context exn "while connecting to %s" host
```
For tests, hide backend details:
```ocaml
Eio.Exn.Backend.show := false
```
## Testing with Eio_mock
Library: `eio.mock` (not `eio_mock`)
### Test Setup Pattern
```ocaml
let setup_test f () =
Mirage_crypto_rng_unix.use_default (); (* or initialize RNG *)
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let fs = Eio.Stdenv.fs env in
let tmp = Eio.Path.(fs / Filename.get_temp_dir_name () / "test-dir") in
(try Eio.Path.rmtree tmp with _ -> ());
Eio.Path.mkdirs ~exists_ok:true ~perm:0o755 tmp;
Fun.protect
~finally:(fun () -> try Eio.Path.rmtree tmp with _ -> ())
(fun () -> f ~sw tmp)
let test_something = setup_test @@ fun ~sw tmp ->
(* test code here *)
```
### Mock Flow
```ocaml
let test_api_call () =
Eio_main.run @@ fun _env ->
let flow = Eio_mock.Flow.make "response" in
(* IMPORTANT: Always end with `Raise End_of_file *)
Eio_mock.Flow.on_read flow [
`Return "{\"ok\": true}";
`Raise End_of_file;
];
(* use flow *)
```
### Simulating Chunked Data
```ocaml
let test_partial_reads () =
Eio_main.run @@ fun _env ->
let flow = Eio_mock.Flow.make "chunked" in
Eio_mock.Flow.on_read flow [
`Return "\x00\x01"; (* First 2 bytes *)
`Return "\x02\x03"; (* Next 2 bytes *)
`Raise End_of_file;
];
(* Parser must handle values spanning chunks *)
```
### Mock Network
```ocaml
let test_network () =
Eio_main.run @@ fun _env ->
let net = Eio_mock.Net.make "mocknet" in
let flow = Eio_mock.Flow.make "conn" in
Eio_mock.Net.on_connect net [`Return flow];
Eio_mock.Flow.on_read flow [`Return "dRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.