This review is focused on Boost.Capy and does not cover Boost.Corosio. It is based on approximately three months of experimentation with Capy in an R&D project on improving support for asynchronous operations in experimental high-energy physics data-processing application frameworks. That work was focused on asynchronous GPU operations in a multithreaded execution environment, including coordination with CUDA execution, rather than network or file I/O. As a result, only the generic asynchronous execution facilities provided by Capy were exercised. In particular, I did not use or evaluate the library's I/O-specific components. For the record, I am not associated with the authors or the C++ Alliance. 1. What is your evaluation of the usefulness of the libraries? I find this library highly useful, as it attempts to address a missing piece in the current C++ ecosystem. While C++20 introduced language support for coroutines, it intentionally didn't include an async library. As a result, the ecosystem still lacks a widely adopted, generic mechanism for representing asynchronous operations that can be communicated across library boundaries and composed between independent libraries. Earlier coroutine libraries such as concurrencpp, cppcoro, libcoro helped explore this design space, but most focused on particular use cases or specific aspects of asynchronous programming rather than defining a general, interoperable contract. Capy builds on those experiences and presents a cohesive design that I believe has the potential to become a common foundation for coroutine-based libraries. In particular, this is a library I wished existed so that when I want to use coroutines, I can rely on a reasonable foundation with some interoperability possible. Beyond the core abstractions and protocols, the library adopts a "batteries included" approach, providing an executor, synchronization primitives, and structured concurrency facilities, making it immediately useful for experimentation and real applications. 2. What is your evaluation of the design? The core of the library consists of the IoAwaitable protocol, executors, and facilities for launching asynchronous operations. On top of that are synchronization primitives based on suspension, facilities for structured concurrency such as when_all, and I/O support classes such as buffers and streams. I find this organization compelling, as it exposes useful building blocks without overly bloating the core library, making it a solid foundation for higher-level libraries implementing specific asynchronous operations and protocols. A similar separation between tasks, execution/scheduler, and context is also observed in other async and coroutine libraries. The core design appears sound and well documented. It addresses key concerns for a coroutine library, including the propagation of allocators, execution environment, and cancellation support. The protocol enables composition of tasks and supports implementing custom coroutine types, awaitables, and executors, as well as building adapters for types originating from other coroutine libraries. Due to the nature of coroutines, interoperability between different coroutine libraries is inherently limited. The advantage of Capy is that it clearly defines and documents its design and protocol making it easier to build an adapter. The protocol does not restrict the kinds of handlers that can be used in awaitables, so common strategies such as callbacks or polling can be implemented. The library is also not tied to a particular executor type, allowing custom executors to be integrated as well, including wrappers that submit work to thread pools already present in an application. One aspect the design handles particularly well is the explicit distinction between two continuation modes: continuation on the same execution resource, which can avoid unnecessary overhead, and rescheduling onto another execution context, for example by enqueuing the continuation. In Capy, both models are available, and authors of custom awaitables can explicitly choose the appropriate behavior without workarounds. 3. What is your evaluation of the implementation? I did not investigate the implementation of the I/O classes such as streams and buffers. For the remaining parts, the code is readable and appears to be of good quality. The authors are consistent with the overall design and avoid common problems such as unnecessary suspensions to query the execution environment from within a coroutine. The use of `thread_local` storage in the plumbing of allocators may initially raise concerns; however, its usage appears to be justified and well isolated. The library was used in a multithreaded application where tasks may resume on different threads without any observed issues. In a test setup involving multiple executors, all continuations were executed on the expected execution resources, and nothing appeared to escape the intended execution context. Exception propagation across awaitables and tasks works as expected; in the application I used, the overhead on the optimistic path was negligible. I did not exercise cancellation beyond simple examples, but it also appears to be viable based on the available interfaces and observed behavior. The library does exhibit the usual challenges related to the lifetime of objects captured by coroutines, although this is not specific to Capy and is explicitly addressed in the documentation. The library appears to depend primarily on standard C++, with only a few platform-specific workarounds for compatibility. It compiled without issues on Linux with GCC 14, 15, and 16, as well as Clang 19 and 22, in both C++20 and C++23. One very pedantic thing I spotted, in a few places, `static_assert(sizeof(A) == 0,` is used to invalidate remaining branches in `if constexpr`, which in practice compiles but isn't legit, see P2593. 4. What is your evaluation of the documentation? I found the documentation to be of high quality and mostly up-to-date, in some places maybe a bit too verbose. It clearly explains the API, provides comprehensive user guides and tutorials, and also includes the rationale behind the design decisions as well as comparisons with other libraries from the domain. I found it very helpful while working with the library and referred to it when needed. In particular it appears to be enough get a grasp of the core concepts and start writing custom awaitables and executors. The documentation also includes introductory chapters on coroutines, concurrency, and parallelism. I do not have a strong opinion on whether this is the best place for such an overview. One aspect I found somewhat concerning is the introduction of `thread_local` storage together with suggested use cases. This may not be appropriate guidance for newcomers, as correct usage of `thread_local`, particularly in asynchronous contexts, is error-prone. One improvement I would suggest is adding a search function, as I occasionally struggled to locate specific information when I couldn't remember which page contained the section I was looking for. 5. Have you used either or both libraries? What was your experience? I did not use Corosio. I did, however, use Capy in an R&D project, where I ported a CUDA-based variant of a high-energy physics particle track reconstruction library with GPUs algorithms and compared it against other ports based on stdexec, Boost.Fiber, and TBB-based suspension. https://github.com/cern-nextgen/wp1.7-traccc In this setup we want to process in parallel several directed acyclic graphs of dependencies between data-transformations, where some of the data-transformations may invoke asynchronous GPU operations such as memory copies or launching kernels. The fibers/coroutines are used to suspend the data-transformations until relevant async operations are finished so other data-transformation can be executed in meantime without blocking CPU. The coroutines/fibers are used only in orchestrating, no coroutines/fibers are supported in the kernels. The experience with Capy was very satisfactory. In particular the protocol is easy to reason about. In benchmarks, performance was essentially the same as stdexec and TBB-based suspension suggesting that coroutine overhead is negligible for this application. From a developer experience perspective, I consider Capy to have significant advantages over stdexec: compilation times were shorter, error messages were clearer, the documentation was available and useful, and the abstraction contract for implementing custom components was substantially simpler, enabling more concise implementations. As an example, several strategies for handling completion of CUDA operations were explored, including polling, callbacks, and execution on a dedicated thread. This required implementing custom awaitables. One such awaitable checks whether an operation has completed; if so, it resumes execution, otherwise it schedules another check on the current executor. Implementing this with Capy was straightforward and expressive. In contrast, achieving the same behavior with stdexec was much less clear. For now it was implemented using `repeat_until`, which is a stdexec-specific extension and IIRC was not standardized as part of C++26. One of the conclusions from the project was that for this use-case any sane form task type standardized be it senders, pure-coroutines, would be acceptable as long as as it would provide a common interface for exposing asynchronous operations across library boundaries. Having said that, from my perspective, senders address two concerns simultaneously: asynchronous execution and heterogeneous programming (single-source code that can be compiled for both CPUs and GPUs from different vendors). The long-term adoption of the heterogeneous part remains to be seen. For asynchronous programming alone, however, I found coroutine and in particular Capy's model to be significantly more natural and expressive. 6. Are the libraries ready for inclusion in Boost? I would be happy to see this library as part of Boost and don't see any critical flaws that need to be addressed. 7. If not, what changes would you recommend before acceptance? - 8. Do the libraries fit well within the existing Boost ecosystem? The library appears to partially overlap with the design space of existing Boost libraries such as Asio and Cobalt. At the same time, it is noticeably different, as it proposes a new model built around coroutines from the ground up, whereas coroutine support in those libraries is layered on top of a different underlying execution model. For example, while evaluating coroutine libraries for the R&D project, I initially investigated Asio and Cobalt but concluded that they were not a good fit for project requirements (parallel execution, non-I/O, ...) and decided not to explore them further. In contrast, I see Capy as addressing a wider space and potentially providing a stronger foundation for coroutine-based development. I can also imagine that including Capy in Boost could foster a new ecosystem around its programming model, encouraging the development of Capy-compatible interfaces for existing Boost libraries. 9. Are there API, naming, usability, extensibility, or implementation concerns that should be addressed? I did not encounter any critical issues while evaluating the library. My only suggestion is that presenting Capy primarily as an I/O library may understate its broader applicability, as I found it useful in contexts beyond I/O. In my view, the library consists of a generic asynchronous execution model, with I/O facilities built on top of it rather than defining its scope. In particular, the name `IoAwaitable` suggests a close association with I/O, whereas the protocol actually describes a convention for sharing an execution context that is independent of I/O and can be applied to arbitrary asynchronous operations. A name that reflects this more general role might better communicate the abstraction that Capy provides. --- Verdict I vote ACCEPT.