Expand description
The Zyris protocol stack behind one name.
A Zyris node dials a server over one websocket, announces typed capabilities — named, versioned sets of tools with JSON-Schema’d arguments — and, on the same connection, consumes the capabilities the server announces back. This crate is the whole stack behind one dependency:
zyris = { version = "0.2", features = ["full", "tls-ring"] }use zyris::{Node, NodeKind};
let node = Node::builder().name("my node").kind(NodeKind::Service).build()?;
// `connect` keeps the link up across drops; `Node::dial` is the single attempt underneath it.
let link = node.connect("wss://attacca.cc/api/zyris/v1/ws", "znt_the_node_token").await?;
link.wait_closed().await?;§Dialling needs a TLS provider, and it is yours to name
wss:// is TLS, rustls does TLS, and rustls has no cipher suite of its own: it reads its
crate features and, when they name no provider, it panics on the first connection. That
panic is deferred all the way to runtime — there is no compile_error! for it — so a build
with none is green, starts, announces, and dies the moment it dials.
So neither provider is on by default and this crate answers the question itself. Turn on exactly one:
| Feature | Provider | What it costs to build |
|---|---|---|
tls-ring | ring | a working cc |
tls-aws-lc | aws-lc-rs | a working cc, and cmake off its nine named targets |
Both compile C, which is why neither is default: cargo add zyris stays buildable on a
machine with no toolchain, and everything short of reaching the network works there —
declaring capabilities, serving them over another transport, the wire types. A build that
skipped this step and dials anyway is refused by ConnectError::NoTlsProvider, before a
socket is opened, naming both features. An application that installs its own provider with
rustls::crypto::CryptoProvider::install_default is believed and needs neither.
enroll names tls-ring for you, because there is no such thing as enrolling without TLS:
it is an HTTPS device-grant flow, and reqwest panics while building its client rather than
on a request when no provider is installed. Adding tls-aws-lc alongside overrides the choice.
p2p reaches a provider too, through iroh — that one is a property of wanting QUIC rather than
something this crate decided.
That is the half a node does on every start. The other half — enrolling once, keeping the
account credential, and minting a node token from it — is spelled out end to end on
zyris::enroll, behind the enroll feature (so it is not a link here: under default
features that item does not exist). Capability declarations live in zyris::caps, behind
caps; what a node implements is the node’s own decision, which is why nothing published
here makes it.
Implementations of those declarations are not here on purpose: what a node offers is the
node’s decision. Reference ones are separate crates, added beside this one as you want them —
zyris-fs, zyris-terminal, zyris-transfer, zyris-screen. zyris-input is the exception
and stays git-only: it pins a fork of enigo, and crates.io refuses a manifest naming a git
source. See https://github.com/attacca-cc/zyris-protocol.
§What is where
The runtime — connection state machine, transports, capability announce and accept, the
dial/reconnect loop, device-grant enrollment, the account layer — is re-exported at this
crate’s root, so Node, Connection, Result and everything beside them are named
directly. The layers above the runtime each get a module, and each is behind a feature:
| Module | Feature | What it is |
|---|---|---|
caps | caps | The standard capability catalogue. Declarations only. |
p2p | p2p | Transport that carries Zyris directly between two nodes. |
Each is also a crate of its own (zyris-caps, zyris-attacca, …). Depending on one directly
and on this one at the same time is not a mistake and does not link anything twice: the
module here is that crate.
§Why the runtime lives in zyris-core
Every crate above the runtime depends on the runtime, so the runtime cannot depend on any of
them — Cargo has no cycles. The runtime therefore ships as zyris-core and this crate
re-exports it whole. Nothing about that is visible in a path: zyris::Node and
zyris_core::Node are one type, and a capability written against either serves the other.
Re-exports§
pub use zyris_core;pub use zyris_caps as caps;capspub use zyris_p2p as p2p;p2p
Modules§
- account
enroll - The account credential: what a device grant issues, and what the caller stores.
- enroll
- Self-registration over the OAuth 2.0 Device Authorization Grant (RFC 8628).
- prelude
- proto
- schemars
- Schemars
- serde
- Serde
- testing
- transport
Structs§
- Accept
Options - Account
- A live account credential: the thing that rotates, and the thing node tokens are minted against.
- Account
Builder - Account
Credential - An account’s long-lived identity: the refresh token it re-presents forever, and the access token it presents at each dial.
- Attachment
Ref - Attachment
Trailer - What an attachment’s
s_endcarries. §4.2 allows a trailer on any stream and namessha256as the end-to-end integrity check; for an attachment it is always present, because the receiver has no other way to tell a truncated blob from a short one. - Capabilities
- What this node offers, changeable while it is connected.
- Capability
Descriptor - Capability
Handle - Chunk
- Code
- What a person has to be shown in order to approve this node.
- Connection
- Connection
Info - Enroll
Request - What a node asks to be enrolled as. The scopes are granted with the credential and never widen afterwards, so this is the one moment they can be chosen.
- Enrollment
- One enrollment attempt in progress: the code to show, and the poll that resolves it.
- Incoming
Call - Link
client - A connection this crate keeps up.
- Node
- Node
Builder - Node
Spec - What a node is asked to be registered as.
scopesis a request, not a grant: the server clamps it to what this account credential was given. - Node
Token - A minted node token and the identity it carries.
znt_tokens do not expire and are never rotated, so nothing here has to be handed back to the caller’s storage on a schedule — but it is the only copy, and this crate does not keep one. - Payload
- RawIncoming
Stream - Rotate
Error - The caller’s own words for why it could not store a rotated credential.
- Streaming
- Tool
Descriptor - Wire
Error
Enums§
- Blob
- Call
Limit - How long one call of a tool may take to answer.
- Close
Reason - Connect
Error - Why a dial did not produce a connection, in the four shades a dialler acts on differently.
- Datum
- Enroll
Error - Why an enrollment did not produce a credential.
- Error
Code - Node
Kind - Outgoing
- Progress
- Where one poll left the grant.
- Register
Error - Why an account credential could not mint a node token.
- Serialization
- Transfer
- Transport
Error
Constants§
- DEFAULT_
SERVER_ URL - The deployment a node reaches with no configuration at all.
- INLINE_
BLOB_ MAX - How many bytes a
Blob::Inlinemay carry before it should be an attachment instead. - MAX_
HYDRATE_ BYTES - How much a generated client will collect into memory to make an attachment look inline. Sized
for the datums a tool call plausibly returns — a screenshot, a document — rather than for bulk
transfer, which has
file_io.read_streamand its chunked stream.
Traits§
Functions§
- decode_
call - encode_
response - encode_
streaming - enroll
- Begin enrolling this node. The returned value carries the code a person has to approve.
- machine_
name - This machine’s short name, or
Nonewhen it has nothing usable to say. - unknown_
tool