Recent from talks
Nothing was collected or created yet.
Cap'n Proto
View on Wikipedia| Cap'n Proto | |
|---|---|
| Original author | Kenton Varda |
| Stable release | |
| Repository | github |
| Written in | C++ |
| Type | Remote procedure call framework, serialization format and library, IDL compiler |
| License | MIT License |
| Website | capnproto |
Cap’n Proto is a data serialization format and Remote Procedure Call (RPC) framework for exchanging data between computer programs. The high-level design focuses on speed and security, making it suitable for network as well as inter-process communication. Cap'n Proto was created by the former maintainer of Google's popular Protocol Buffers framework (Kenton Varda) and was designed to avoid some of its perceived shortcomings.
Technical overview
[edit]IDL Schema
[edit]Like most RPC frameworks dating as far back as Sun RPC and OSF DCE RPC (and their object-based descendants CORBA and DCOM), Cap'n Proto uses an Interface Description Language (IDL) to generate RPC libraries in a variety of programming languages - automating many low level details such as handling network requests, converting between data types, etc. The Cap'n Proto interface schema uses a C-like syntax and supports common primitives data types (booleans, integers, floats, etc.), compound types (structs, lists, enums), as well as generics and dynamic types.[1] Cap'n Proto also supports object-oriented features such as multiple inheritance, which has been criticized for its complexity.[2]
@0xa558ef006c0c123; # Unique identifiers are manually or automatically assigned to files and compound types
struct Date @0x5c5a558ef006c0c1 {
year @0 :Int16; # @n marks order values were added to the schema
month @1 :UInt8;
day @2 :UInt8;
}
struct Contact @0xf032a54bcb3667e0 {
name @0 :Text;
birthday @2 :Date; # fields can be added anywhere in the definition, but their numbering must reflect the order in which they were added
phones @1 :List(PhoneNumber);
struct PhoneNumber { # Compound types without a static ID cannot be renamed, as automatic IDs are deterministically generated
number @0 :Text;
type @1 :PhoneType = mobile; # Default value
enum PhoneType {
mobile @0;
landline @1;
}
}
}
Values in Cap'n Proto messages are represented in binary, as opposed to text encoding used by "human-readable" formats such as JSON or XML. Cap'n Proto tries to make the storage/network protocol appropriate as an in-memory format, so that no translation step is needed when reading data into memory or writing data out of memory.[note 1] For example, the representation of numbers (endianness) was chosen to match the representation the most popular CPU architectures.[3] When the in-memory and wire-protocol representations match, Cap'n Proto can avoid copying and encoding data when creating or reading a message and instead point to the location of the value in memory. Cap'n Proto also supports random access to data, meaning that any field can be read without having to read the entire message.[4]
Unlike other binary serialization protocols such as XMI, Cap'n Proto considers fine-grained data validation at the RPC level an anti-feature that limits a protocol's ability to evolve. This was informed by experiences at Google where simply changing a field from mandatory to optional would cause complex operational failures.[5][note 2] Cap'n Proto schemas are designed to be flexible as possible and pushes data validation to the application level, allowing arbitrary renaming of fields, adding new fields, and making concrete types generic.[6] Cap'n Proto does, however, validate pointer bounds and type check individual values when they are first accessed.[4]
Enforcing complex schema constraints would also incur significant overhead,[note 3] negating the benefits of reusing in-memory data structures and preventing random access to data.[7] Cap'n Proto protocol is theoretically suitable[8] for very fast inter-process communication (IPC) via immutable shared memory, but as of October 2020 none of the implementations support data passing via shared memory.[9] However, Cap'n Proto is still generally considered faster than Protocol Buffers and similar RPC libraries.[10][11]
Networking
[edit]Cap'n Proto RPC is network aware: supporting both handling of disconnects and promise pipelining, wherein a server pipes the output of one function into another function. This saves a client a round trip per successive call to the server without having to provide a dedicated API for every possible call graph. Cap'n Proto can be layered on top of TLS[12] and support for the Noise Protocol Framework is on the roadmap.[13] Cap'n Proto RPC is transport agnostic, with the mainline implementation supporting WebSockets, HTTP, TCP, and UDP.[14]
Capability security
[edit]The Cap'n Proto RPC standard has a rich capability security model based on the CapTP protocol used by the E programming language.[15]
This section needs expansion. You can help by adding to it. (March 2021) |
As of October 2020, the reference implementation only supports level 2.[13]
Comparison to other serialization formats
[edit]Cap'n Proto is often compared to other zero-copy serialization formats, such as Google's FlatBuffers and Simple Binary Encoding (SBE).[7][16]
Adoption
[edit]Cap'n Proto was originally created for Sandstorm.io, a startup offering a web application hosting platform with capability-based security. After Sandstorm.io failed commercially, the development team was acqui-hired by Cloudflare,[17] which uses Cap'n Proto internally.[18]
Notes
[edit]- ^ Unlike Apache Arrow, Cap'n Proto's in-memory values are not suited for sharing mutable data
- ^ Marking a field as required was removed from Protocol Buffers 3.
- ^ Assuming the data has already been allocated (e.g. in network buffers, read from disk) access becomes O(1). Additional serialization/deserialization steps (as required to inspect values) would limit performance to O(n).
References
[edit]- ^ Varda, Kenton. "Cap'n Proto Schema Language". Archived from the original on 2015-03-17. Retrieved 2020-09-05.
- ^ Denhardt, Ian (June 2019). "A Critique of the Cap'n Proto Schema Language". zenhack.net. Archived from the original on 2019-06-26. Retrieved 2020-10-10.
- ^ Varda, Kenton. "Cap'n Proto: Introduction". Cap'n Proto Homepage. Archived from the original on 2015-03-17. Retrieved 2020-11-09.
- ^ a b Varda, Kenton. "Cap'n Proto: Encoding Spec". Cap'n Proto. Archived from the original on 2015-03-17.
- ^ Varda, Kenton. "FAQ § How do I make a field "required", like in Protocol Buffers?". Cap'n Proto. Archived from the original on 2015-03-18. Retrieved 2020-09-05.
- ^ "Cap'n Proto: Schema Language". capnproto.org. Retrieved 2020-10-10.
- ^ a b "Cap'n Proto: Cap'n Proto, FlatBuffers, and SBE". capnproto.org. Retrieved 2020-10-10.
- ^ Richardson, Corey (October 2016). "Robigalia: An Operating System for the Modern Era". robigalia.gitlab.io. Archived from the original on 2018-09-15. Retrieved 2020-10-10.
- ^ Kenton, Varda (May 3, 2017). "Why is not intended that in-memory state be in Cap'n Proto / Protobuf objects?". Hacker News (news.ycombinator.com). Retrieved 2020-10-10.
- ^ Naughton, Chris (Aug 24, 2018). "Protocol Benchmarks". Github. Archived from the original on 2018-08-30. Retrieved 2020-09-05.
- ^ Parimi, Dinesh (2019). "Datacenter Tax Cuts: Improving WSC Efficiency Through Protocol Buffer Acceleration" (PDF). Archived (PDF) from the original on 2020-09-06. Retrieved 2020-09-05.
- ^ "Cap'n Proto: Road Map". capnproto.org. Retrieved 2020-10-10.
- ^ a b "Roadmap". Cap'n Proto. 2021-03-13. Archived from the original on 2015-03-17.
- ^ "Cap'n Proto: C++ RPC". capnproto.org. Retrieved 2020-10-10.
- ^ "RPC Protocol". Cap'n Proto. Archived from the original on 2015-03-18.
- ^ "Why flatbuffers instead of capnp?".
- ^ Varda, Kenton (13 Mar 2017). "The Sandstorm Team is joining Cloudflare". Sandstorm.io. Archived from the original on 2017-03-13. Retrieved 2020-09-05.
- ^ Zhi, Jiale (2013). "Introducing lua-capnproto: better serialization in Lua". Archived from the original on 2014-03-06. Retrieved 2020-09-05.
Cap'n Proto
View on GrokipediaHistory and Development
Origins and Creation
Cap'n Proto was created by Kenton Varda, who served as the primary author of Protocol Buffers version 2 during his time at Google, drawing on that experience to design a more efficient successor. After leaving Google, Varda initiated the project to address persistent limitations he encountered in data serialization formats, informed by years of hands-on use and extensive user feedback on Protocol Buffers.[1][5] The core motivations stemmed from the inefficiencies of existing systems like Protocol Buffers, particularly the overhead of encoding and decoding data, which required additional processing steps and memory allocations that slowed performance in real-world applications. Varda aimed to eliminate these bottlenecks while incorporating a built-in remote procedure call (RPC) mechanism, which Protocol Buffers lacked natively, to enable seamless object-oriented communication without the need for separate RPC frameworks. This drive for optimization was rooted in Varda's observation that serialization often became a performance chokepoint in distributed systems.[1] Initial development began in 2013 specifically for the Sandstorm.io platform, a self-hosting environment for web applications that required robust, secure inter-process communication to support sandboxed, multi-tenant deployments. Sandstorm's architecture demanded a format capable of handling capability-based security to isolate applications while allowing efficient data exchange between them and the host system. The project was first publicly announced on April 1, 2013, with the initial beta release (version 0.1) on June 27, 2013, marking the start of its open-source journey.[2][6][7][5] Early design goals centered on creating a compact binary format that outperformed both JSON in readability-to-speed trade-offs and Protocol Buffers in raw efficiency, targeting "infinity times faster" performance through direct memory access without serialization steps. Integrated native RPC and a capability security model were prioritized from the outset to support secure, high-performance interactions in constrained environments like Sandstorm, emphasizing zero-copy data handling and schema-driven evolution for long-term compatibility.[1]Key Releases and Milestones
Cap'n Proto was first publicly announced as open-source software on April 1, 2013, under the Apache License 2.0, with the initial beta release (version 0.1) following on June 27, 2013.[6][7] A beta version 0.1 provided core serialization support for C++ including basic types, lists, structs, and dynamic schema loading.[8] In December 2014, version 0.5 was released, enhancing the RPC system with features like generics and improved Visual C++ support, contributing to greater stability in remote procedure calls.[9] A key milestone in early security efforts occurred in March 2015, when fuzzing tests uncovered integer overflow vulnerabilities in the C++ implementation, leading to patches and the addition of runtime overflow checks to prevent denial-of-service attacks.[10] The development team, previously behind Sandstorm.io, joined Cloudflare in March 2017, redirecting efforts toward scalable cloud infrastructure and integrating Cap'n Proto into high-performance environments like content delivery networks.[11] This shift facilitated its adoption within Cloudflare Workers, where it powers inter-process and machine communication for serverless applications starting around 2017-2018.[12][13] Version 0.6 arrived in May 2017, after over two years of refinements, introducing Windows support via Visual Studio, JSON interoperability, and HTTP-over-RPC capabilities to broaden platform compatibility.[14] Cap'n Proto reached version 1.0 on July 28, 2023, establishing a long-term stable branch with performance optimizations, such as reduced memory allocations in the C++ library, and strengthened security features including better handling of dynamic capabilities.[2] The project continued evolving, culminating in the stable release of version 1.2.0 on June 15, 2025.[15][16]Core Design Principles
Zero-Copy Data Interchange
Cap'n Proto implements zero-copy data interchange by encoding messages in a binary format that serves directly as the in-memory representation, allowing readers to access data through offsets into a single contiguous buffer without any parsing, copying, or deserialization steps.[1] This approach ensures that the structured data remains in its original memory location, enabling direct manipulation via generated accessors that operate on the underlying buffer.[17] The primary benefits of this zero-copy mechanism include achieving access speeds comparable to direct RAM operations, supporting random access to any field without sequential scanning, and facilitating incremental reading where only required portions of the message are processed.[1] It also promotes efficient memory usage by avoiding the allocation of intermediate objects, which is particularly advantageous for high-throughput applications handling large or complex data structures.[18] To manage memory, Cap'n Proto employs arena allocation, where messages are built within segmented buffers that grow dynamically without relocating existing data, ensuring cache locality and minimal fragmentation.[18] This system is compatible with memory mapping techniques like mmap, allowing messages from files or network streams to be mapped directly into process address space, with the operating system loading only the accessed segments on demand.[1] For scenarios requiring compact transmission over networks, Cap'n Proto provides an optional packing feature that compresses the message by removing zero-valued padding bytes while preserving the zero-copy accessibility upon unpacking.[12] Packing encodes words using a tag byte followed by non-zero bytes, efficiently handling spans of zeros (e.g., via a 0x00 tag for consecutive zeros), resulting in message sizes similar to those of Protocol Buffers without necessitating full re-encoding.[18] In this mode, the format is no longer strictly zero-copy during transmission but restores it after unpacking, maintaining overall efficiency.[19] Performance benchmarks demonstrate that Cap'n Proto's zero-copy design eliminates serialization overhead entirely for in-memory operations, yielding "infinity times" faster access compared to formats like Protocol Buffers that require encoding and decoding.[1] When packing is applied for network use, it remains faster than Protocol Buffers due to reduced CPU costs in compression and the absence of parse-time overhead.[12] This efficiency extends to enabling low-latency remote procedure calls by passing message buffers directly between processes.[1]Schema Evolution and Compatibility
Cap'n Proto provides built-in support for schema evolution, enabling protocols to change over time while preserving forward and backward compatibility without requiring data migration or version-specific code paths.[20] Forward compatibility allows new readers to interpret old data by using default values for newly added fields, while backward compatibility ensures old readers can process new data by ignoring unknown fields.[19] This design relies on the Interface Definition Language (IDL) to define schemas with ordinal numbers (@N annotations) that track the order of additions, ensuring structural stability.[20] Adding fields is the primary evolution mechanism, where new fields are assigned higher ordinal numbers, such as appending@3 :Text for a birthdate after existing @0 and @1 fields.[20] Old binaries skip these unknown fields during deserialization, treating them as absent, while new binaries supply defaults (e.g., empty strings or zero values) for fields missing from old data.[19] Unlike some formats that discard unknowns, Cap'n Proto retains them in the wire format via embedded pointers with type and size information, allowing recursive copying of messages without schema knowledge and preserving extensibility for future readers.[19]
Unions and groups further facilitate evolution by grouping related fields or enforcing mutual exclusivity. Unions, defined with :union, use a tag to indicate the active variant, enabling new members to be added without disrupting old discriminators; for instance, extending an employment :union with a new @2 :[Teacher](/page/Teacher) option allows prior versions to default to known cases.[21] Groups encapsulate fields logically (e.g., address :group { street @0 :Text; [city](/page/City) @1 :Text; }), permitting additions within the group—such as a new zipCode @2 :UInt16—while maintaining wire compatibility, as the layout remains contiguous and ignorable for unknowns.[22] Optional fields are simulated using Void in unions (e.g., optionalBirthdate @3 :Union { present @0 :Date; absent @1 :Void; }), avoiding null pointers and ensuring type safety during changes.[20]
Versioning is managed through schema fingerprints—unique 64-bit hashes embedded in file headers and type declarations (e.g., @0xdbb9ad1f14bf0b36)—which serve as brand identifiers to verify schema identity without enforcing strict validation at the serialization layer.[23] These fingerprints allow applications to detect mismatches optionally, supporting loose coupling where messages can be exchanged across versions as long as basic layout rules are followed, though no automatic enforcement occurs during encoding or decoding.[20]
Deletions and renames pose challenges, as ordinal numbers cannot be reused or altered without breaking compatibility, potentially leading to data misalignment.[20] Instead, Cap'n Proto recommends deprecation via groups and inheritance: mark obsolete fields within a group as ignored (e.g., by documentation or annotations), then introduce a new group or inherited struct with renamed equivalents, migrating data gradually without immediate wire breakage.[22] For interfaces, multiple inheritance (e.g., ExtendedPerson extends Person) extends methods without altering base schemas, preserving call sites in legacy code.[24]
While these features enable robust evolution at the protocol level, trade-offs include the need for application-level enforcement of compatibility policies, such as runtime checks on fingerprints or custom validation to prevent subtle semantic drifts from unchecked additions.[20] Developers must adhere to guidelines like avoiding ordinal reuse and documenting defaults to maintain interoperability across distributed systems.[20]
Technical Overview
As of version 1.2.0 (June 2025), the core design remains as described below, with implementation improvements such as full Windows support.[15]Interface Definition Language (IDL)
Cap'n Proto employs a schema language, often referred to as its Interface Definition Language (IDL), to define structured data types and service interfaces in a strongly-typed manner. This language uses a C-like syntax for declarations, enabling developers to specify structs for composite data, enums for symbolic constants, unions for variant types, lists for sequences, and interfaces for method definitions. Files with the.capnp extension contain these definitions, which are compiled into language-specific code to ensure type safety and efficient runtime access.[23]
The supported types in the IDL encompass primitives such as Void, Bool, signed and unsigned integers from Int8 to Int64, and floating-point values like Float32 and Float64, alongside composites including Text for UTF-8 strings and Data for arbitrary bytes. Composites extend to user-defined structs with named fields, each assigned an ordinal via @N notation (e.g., @0 for the first field), lists parameterized by any type (e.g., List(Int32)), and interfaces that declare methods with parameter and return types. Generics are supported through parameterized structs and interfaces, such as struct Map<Key, Value>, allowing reusable definitions. Structs and interfaces also permit multiple inheritance by extending other types, promoting code reuse while maintaining schema clarity. Unions are embedded within structs to represent mutually exclusive options, ensuring only one branch is set at a time.[23]
Annotations enhance the IDL's expressiveness, allowing metadata attachment to files, types, fields, and methods using @identifier(value) syntax, which can specify defaults (e.g., age @1 :UInt16 = 18), constraints like field ordering, or documentation via post-declaration comments (e.g., # Age in years.). For remote procedure calls, pipeline operators (->>) enable method chaining in interface definitions, facilitating asynchronous result pipelining. The compilation process involves the capnp compile tool, which processes .capnp files and generates idiomatic code for languages like C++, Java, or Go, integrating directly with the runtime for zero-copy data handling.[23]
Representative examples illustrate the IDL's conciseness. A basic struct might be defined as:
struct Person {
name @0 :Text;
age @1 :UInt16;
email @2 :Text;
}
struct Person {
name @0 :Text;
age @1 :UInt16;
email @2 :Text;
}
enum ContactType {
mobile @0;
home @1;
work @2;
}
enum ContactType {
mobile @0;
home @1;
work @2;
}
union Shape {
circle @0 : (radius : Float64);
rectangle @1 : (width : Float64, height : Float64);
}
union Shape {
circle @0 : (radius : Float64);
rectangle @1 : (width : Float64, height : Float64);
}
interface File {
read @0 (offset :UInt64, size :UInt32) -> (data :Data);
write @1 (data :Data) -> (bytesWritten :UInt32);
}
interface File {
read @0 (offset :UInt64, size :UInt32) -> (data :Data);
write @1 (data :Data) -> (bytesWritten :UInt32);
}
Binary Format and Data Structures
Cap'n Proto employs a compact, binary encoding scheme designed for efficient in-memory representation and direct access without deserialization. Messages are structured as trees of typed objects, using 64-bit little-endian words, with all primitives encoded in little-endian format and objects aligned to 8-byte word boundaries.[18] This format divides messages into segments, each containing data and pointers, enabling zero-copy access to the underlying structure.[18] The binary layout organizes content into distinct sections within each segment: the root object, followed by inline data words, then pointer words. The first word of the first segment is a pointer to the root struct, specifying its offset, data section size in words, and pointers section size in words.[18] Subsequent segments, if present, are referenced via far pointers and contain additional objects, allowing messages to span multiple non-contiguous memory regions. Data sections store primitive values tightly packed as possible, with possible padding of up to 7 bytes at the end to align to a word boundary, while pointer sections hold references to other objects, ensuring a segmented structure that supports efficient random access.[18] Pointers in Cap'n Proto are 64-bit words that use an offset-based system for navigation, with offsets expressed as signed 30-bit integers in units of 8-byte words. Positive offsets indicate forward jumps from the current pointer's location, while negative offsets denote backward jumps, facilitating relative addressing within and across segments.[18] Each pointer includes a 2-bit tag to denote its type: 00 for a struct pointer, 01 for a list pointer, 10 for a far pointer (which embeds a 32-bit segment ID and 29-bit offset), and 11 for a capability pointer. For struct pointers, the remaining bits specify the number of data words and pointer words in the target struct; list pointers include element count and size bits (0-7 for primitive widths, or 7 for composite types like sub-structs).[18] Core data structures emphasize density and predictability. Structs consist of a fixed-size data section for primitives (e.g., integers, floats) packed tightly with possible up to 7 bytes padding at the end for alignment, followed by a pointers section; fields without explicit values default to zero or schema-defined constants, using presence bits implicitly rather than null indicators.[18] Lists are represented as flat, contiguous arrays with a leading word containing the element count (29 bits) and size tag (3 bits), supporting both primitive elements (e.g., uint8 arrays) and composite ones like nested structs, where the list points to a sequence of sub-objects.[18] This design avoids variable-length encodings for primitives, ensuring constant-time access to any element. For example, a simple struct pointer might encode as08 00 00 00 03 00 02 00, where the offset is 2 words forward, with 3 data words and 2 pointer words.[18]
The file or message structure begins with the 8-byte header, followed by the root segment's data and pointers, and optional additional segments linked via far pointers. Cap'n Proto supports a "packed" mode for storage or transmission, which applies LZ4 compression to zero-filled words and bit-packing to reduce the size of sparse messages, while preserving the logical structure for unpacking.[18] This mode is optional and reversible without altering the in-memory layout.[18]
To ensure platform independence, Cap'n Proto makes no assumptions about host endianness or alignment beyond little-endian word ordering, explicitly defining bit-packing for sub-word fields (e.g., booleans as single bits in a word). All multi-byte values are word-aligned, and structs avoid padding beyond the allowed 7 bytes in data sections, relying on the schema to interpret the exact layout at compile time.[18] This approach minimizes portability issues across architectures, as the format is self-describing in terms of offsets and types without relying on external padding conventions.[18]
Remote Procedure Call (RPC) System
Cap'n Proto's RPC system provides a built-in mechanism for distributed method calls, designed to enable efficient, low-latency communication between client and server processes over bidirectional streams such as TCP or WebSockets.[25] The protocol is fundamentally promise-based, allowing asynchronous operations where calls return promises that can be chained or waited upon, facilitating concurrency without blocking.[25] It supports pipelines, which chain multiple calls into a single round trip to minimize latency, and joins, which verify reference equality across promises to handle concurrent operations effectively.[25] This design leverages Cap'n Proto's zero-copy serialization, where messages are encoded in the binary format for direct memory access during transmission.[25] A typical RPC call begins with a request message containing a method identifier and parameters, structured as a capability invocation on the remote object.[25] The server processes the request and responds with a message carrying the results or an error, which is propagated as a "disconnected" exception if the connection fails or the call aborts.[25] Promises in the system support methods likewait() for synchronous resolution and then() for chaining callbacks, enabling developers to build responsive applications without manual threading.[25] Error handling integrates seamlessly with the promise model, ensuring that failures in pipelined calls do not cascade uncontrollably.[25]
The RPC protocol is transport-agnostic, relying on abstract "connections" that can be implemented over various protocols through adapters, including HTTP/2 for web compatibility and UDP for lower-latency scenarios.[25] It defines four capability levels to progressively enable advanced features: Level 1 supports basic pipelining, Level 2 introduces persistent capability tokens for stateful interactions, Level 3 allows three-way handshakes for mutual authentication, and Level 4 provides full reference equality across distributed objects.[25] A notable feature is "time-traveling RPC," which records and replays calls using persistent capabilities, aiding in debugging by simulating network conditions without altering production code.[25]
For handling large datasets or real-time data streams, such as video feeds, the system incorporates streaming support via tail calls, where a method can return a capability to a stream endpoint, allowing continuous data flow without buffering the entire payload in memory.[25] This extends the promise model to streaming promises, enabling efficient processing of unbounded data sequences.[25]
Integration with Cap'n Proto's Interface Definition Language (IDL) generates client stubs and server proxies automatically from interface definitions, eliminating the need for boilerplate code to handle message marshaling or connection management.[25] Developers implement only the core method logic, with the runtime managing the full RPC lifecycle, including promise resolution and transport details.[25] This approach, demonstrated in official samples like the calculator client, simplifies building distributed systems.[26]
Capability-Based Security Model
Cap'n Proto employs a capability-based security model inspired by object-capability (ocap) systems, where access to objects is controlled through unforgeable references known as capabilities. These capabilities represent revocable permissions to interact with specific objects, eliminating global namespaces and requiring explicit transfer of references for access. Unlike traditional access control lists (ACLs) or ambient authority models, this approach ensures that permissions are tightly scoped and cannot be escalated without deliberate delegation, aligning with the principle of least authority.[25] In this model, objects serve as endpoints for operations, and capabilities are passed explicitly—often termed "pass-by-capability"—preventing unauthorized discovery or invocation. When an object is created, only its creator holds the initial capability; subsequent access requires the capability to be shared, such as through method parameters or return values in RPC calls. This design avoids confused deputy attacks by ensuring that no implicit or global authorities exist, forcing applications to grant permissions intentionally. Revocability is inherent: when all capabilities to an object are dropped, the object can be garbage-collected, freeing resources and terminating access.[25] Cap'n Proto defines progressive levels of capability support to accommodate varying implementation complexities. Level 1 provides basic object references and promise pipelining, enabling asynchronous method chaining over networks without additional round trips. Level 2 extends this with persistent capabilities, allowing objects to be saved and restored across sessions using tokens managed by the host application. Level 3 introduces three-way interactions for direct peer-to-peer connections between endpoints, while Level 4 adds reference equality and join lists, facilitating multi-party coordination by verifying that multiple parties hold capabilities to the same object. Promised capabilities, part of Level 1, allow pipelined calls on future objects, enhancing efficiency in distributed scenarios.[25] Implementation-wise, capabilities are treated as first-class types in Cap'n Proto's schema, embedded as special pointers within messages, structs, or lists. This integration avoids ambient authority by requiring explicit grants during object construction or transfer, with the runtime enforcing that only held capabilities can be exercised. In RPC contexts, this briefly supports secure distributed invocation by passing capabilities over the wire, maintaining isolation without relying on separate authentication layers.[25] The security benefits are particularly pronounced in multi-tenant environments, such as Cloudflare Workers, where Cap'n Proto's model prevents privilege escalation by confining access to explicitly shared stubs and methods, thereby supporting fine-grained isolation among untrusted parties. This enables least-privilege enforcement in sandboxed systems, reducing attack surfaces compared to models with broader ambient permissions. However, limitations persist: the framework does not provide built-in encryption, deferring to transport-layer security like TLS; applications must correctly implement capability management to avoid leaks; and higher-level features like persistent capabilities require additional host support, potentially complicating adoption.[25][27]Implementations
Official Language Bindings
The official language bindings for Cap'n Proto are the core, maintained implementations provided directly by the project, ensuring full compatibility with its zero-copy serialization, schema evolution, and RPC features. These bindings are hosted under the capnproto GitHub organization and focus on high-performance integration across key programming ecosystems.[3] The primary implementation is the C++ library, which serves as the reference for the entire system. It includes a comprehensive runtime library for message handling, a code generator (capnp tool) to compile .capnp schema files into strongly-typed C++ classes, and full RPC support with capability-based security. For installation, users can leverage package managers such as apt-get install capnproto on Debian/Ubuntu systems, brew install capnp on macOS via Homebrew, or pacman -S capnproto on Arch Linux; alternatively, build from source using the release tarball or Git clone for the latest development version. Usage involves defining schemas in the Interface Definition Language (IDL), compiling them—e.g., capnp compile -oc++ addressbook.capnp generates addressbook.capnp.h and .c++ files—and then instantiating builders or readers for zero-copy data manipulation, such as creating a contact entry with ::capnp::MallocMessageBuilder message; auto contacts = message.initRoot<Addressbook::Contacts>();. This binding is actively maintained with continuous integration (CI) pipelines for major releases, ensuring compatibility across platforms including Windows via CMake or MinGW.[15][3]
The Python binding, pycapnp, provides full support for serialization and RPC, wrapping the C++ core for high-performance data handling and remote calls in Python environments. It includes a code generator to produce idiomatic Python code from .capnp schemas. Installation is via pip with pip install pycapnp, requiring the C++ library; usage involves importing the generated modules and using builders/readers similar to C++, e.g., from addressbook import Addressbook; message = Addressbook.Contacts.new_message();. The binding is maintained under the capnproto organization.[28][29]
The Java binding offers a pure Java implementation of serialization and RPC without native dependencies, suitable for JVM-based projects. It includes a code generator (capnp compile -ojava) to create Java classes from schemas, supporting zero-copy where possible via direct buffer access. Usage example: compile schema to generate classes, then Addressbook.Contacts.Builder contacts = Addressbook.Contacts.newBuilder();. Maintained officially with CI testing.[30]
For JavaScript and TypeScript environments, the official binding is provided through the node-capnp package for Node.js, wrapping the C++ library to expose serialization and RPC functionality, though it incurs some overhead from V8-to-C++ bridging. Installation is straightforward via npm with npm install capnp, requiring Node.js development headers and the C++ library; on Debian/Ubuntu, this includes sudo apt-get install nodejs-dev libcapnp-dev g++. Usage example: load the module with var capnp = require("capnp");, parse a schema-compiled message from a buffer using capnp.parse(Addressbook.Contacts, inputBuffer), and perform RPC calls like client.someMethod("example", 42, {field: "value"}).then(result => console.log(result));. It is maintained via GitHub with CI for stable releases.[31]
The official Rust binding is delivered through the capnp and capnp-rpc crates, providing zero-copy integration with Rust's ownership model for efficient in-memory data traversal and RPC. Installation occurs via Cargo with cargo add capnp for the runtime and capnpc for code generation, which integrates into build.rs scripts to compile schemas during builds. For example, after defining a schema like struct Point { x @0 :Int32; y @1 :Int32; } in point.capnp, running capnp compile -orust point.capnp generates Rust modules; usage then involves builders like let mut [message](/page/Message) = ::capnp::message::Builder::new_default(); let mut point = [message](/page/Message).init_root::<point::Point::Builder>(); point.set_x(10i32); point.set_y(20i32); for zero-copy operations. The RPC system uses capnp-rpc for capability-based calls, with async support via capnp-futures. This binding is maintained under the capnproto organization on GitHub, with CI ensuring compatibility.[32][33]
