Hi Everyone, I do not feel qualified in the domain of asynchronous I/O to provide a responsible review. But let me share some observations instead. I would like to thank the Capy/Corosio team for developing and sharing these libraries. This is a huge scope, a huge effort, a great lot of moving parts and details to tackle. I am not even sure how this can be reviewed with the level of scrutiny that is required. I appreciate the unprecedented level of the design rationale. The library comes not only with sources, tests and library documentation, but also with lots of documents presenting rationale for every tiny decision. The contribution of this library is not only the code that users can use, but also the accumulated (and shared) knowledge that can be used by anyone, for writing their own I/O framework and avoiding the past mistakes. This alone builds my trust in the authors and the quality of the library. The value proposition of Capy and Corosio is not only in providing a faster and easier to use alternative to ASIO. It is also the responsiveness of the authors and openness for contribution. It gives me confidence that if I encounter some problems with the library in the future, they will be solved in a predictable way. Now, the concerns. A couple of things in the IoAwaitable protocol give discomfort: 1. Having to use thread_local storage 2. Having to use the double-call syntax. 3. Having to use pass they stop_token via await_ready (and therefore risk UB when stop_token is queried before the first suspend). Ideally, these things should not be present in a protocol. However, it seems impossible to provide any alternative design, with coroutines as its basic vehicle, that would have fewer problems like these. What can we conclude from this? It looks like C++ coroutines are not well suited for I/O-like flows with environment propagation. You can do it *somehow*: just pass all you need in the coroutine's function parameter list, but it is not ergonomic or type-safe. I think the review of Capy may be exposing a design flaw in coroutines. If the goal of Capy is to provide the best third-party library asynchronous-I/O coroutine implementation, then the current design may indeed be the best (as in "no better design can be thought of"). But if the goal is to aim at standardization, I do not think that such unsafe design would work. The action would rather be, "fix coroutines in the language". This makes me think that coroutines in C++ may be a dead end. This would be consistent with some other observations: scarce adoption in the community and WG21 itself choosing to use a different model for asynchronous flows. One could question one design choice in Capy: why go with coroutines when you have to fight an uphill battle with the language? But then, given that it outperforms ASIO and std::execution, it has clearly earned its place. It surely deserves its place in Boost as "the best you can do with coroutines for I/O". But if I were to consider switching to a different library for async I/O I would also consider/evaluate non-coroutine alternatives. On the usage of error_code and reporting failures. The library doesn't give me a clear picture on how it handles and how I should handle the non-clear-sky situations. For things that represent obvious disappointments -- broken connection, problems on the wire, not enough memory to process a request -- it sometimes returns an error_code and sometimes throws an exception. It looks like the division is: * for things happening on the wire, or in the system's native part of the I/O implementation, use error_code * for problems with resources in the implementation of the library throw exceptions. But then also, the library returns error_codes for situations that are not errors by any measure: for situations that I desire: * Successfully receiving full stream content. * Stopping the running process upon my request. The only model for this that I can adapt is that the contract of stream interaction is similar to the interaction with a human postman: * They can deliver you a parcel * But they can also tell you "I lost your parcel", or "while obtaining the parcel I noticed that the box is half-open", or "I had a car accident, and couldn't deliver your parcel" That is, your success is having had a meeting with the postman and chatted with them and maybe also having obtained the parcel. In that model not receiving a parcel is not an error. This makes sense for the interaction with a single stream, but breaks for the next layer: 1. when you have to interact with two streams at once: pull_from, push_to. 2. when you have "algorithms" such as when_any, when you have to nominate the first successful task. But in the postman model nearly everything is successful. Having read the stream status is success. In the case of push_to/pull_from, you might be interested in knowing which of the two streams was the cause of disappointment. But the interface does not let you get this information. Interaction with two postmen would require two statuses. While the contract of `stream.read_some` is "I promise you nothing else than to inform you what happened", it is not clear to me what the contract of pull_from is. Is it: a) I promise to pump the data from one stream to the other. We will call it a contract violation if I fail. OR b) I will just issue some stream instructions in sequence and tell you what the readouts of controls are. My having told you the readout is already a success; you interpret what this means for you. In this case I do not buy the "ASIO got that right" argument. If ASIO is also unclear about the contract, then ASIO got that wrong also. There are a lot of libraries that are popular, contribute to the success of servers that employ them, but that get their contracts wrong. I am bringing the contract aspect, because I know that the authors of Capy care deeply about this level of clarity. A number of libraries were accepted to Boost while having a muddy contract, and this did not seem to be a show-stopper. My observations are based on reading the documentation and the implementation of some parts of Capy and Corosio, running toy examples and discussing the design aspects with the authors. Disclaimer: I am affiliated with the C++ Alliance, and have occasionally contributed to Capy. Regards, &rzej;