ZyrisDocs

Capability addons

Reuse ready-made file, terminal, desktop and transfer implementations and combine them with your own capabilities.

You do not have to implement every tool before building a node. Capability addons are reusable Rust crates that supply existing implementations. Choose the ones your application needs, register them on your node, and focus on the tools that make your application different.

These addons are libraries compiled into your program, not plugins downloaded by a running node. Installing a crate alone does not announce tools: your program explicitly registers capabilities.

Understand the three layers

  • zyris supplies the runtime, connection and capability registration.
  • zyris-caps, also available as zyris::caps with the caps feature, supplies the standard traits, schemas, generated server wrappers and typed clients. It does not operate the machine.
  • An implementation addon supplies behavior behind a trait. For example, zyris-fs implements FileIo using local files, and FileIoServer makes that implementation callable.

The standard catalogue describes tool names and versions. This page explains how to reuse and extend their implementations.

Choose an addon

Each addon has a detailed guide with setup, typed usage, limits and troubleshooting:

AddonImplementation and wrapperWhat it provides
zyris-fsLocalFileIo, FileIoServerLocal file listing, metadata, reads, writes, edits, removal, directories and streaming reads.
zyris-terminalPtyTerminal, TerminalServerReal PTY sessions, output buffers, terminal screen snapshots and one-shot commands.
zyris-screenHostScreenCapture, ScreenCaptureServerDisplay enumeration and screenshots; HostDisplays supplies the shared display layout.
zyris-inputEnigoInput, InputServerKeyboard and pointer control in the same coordinate space as screenshots.
zyris-transferLocalPeerTransfer, PeerTransferServer; LocalFileTransfer, FileTransferServerResumable peer deliveries and inboxes, plus the agent-facing sending surface.

Not every zyris-* package is an implementation addon. zyris-core, zyris-proto and zyris-macros are runtime, wire and code-generation layers. zyris-p2p is a transport. zyris-attacca declares the server API a node consumes.

Registry releases versus main

File, terminal, screen and transfer addons are published on crates.io. zyris-input is git-only because it pins an enigo fork. These docs track main, while the registry's 0.2.0 release predates the current credential API. Use the same source for the runtime, declarations and addons in one application. The examples here use git throughout; for registry releases, use compatible registry versions throughout and consult their versioned docs.rs documentation.

The detailed addon guides and their Rust snippets were checked against d9975e6. Platform permissions and backend limitations still require testing on the actual host.

Combine ready-made tools with your own

This complete example adds file and terminal addons beside one custom health.status tool. There is no need to fork the addons or recreate their schemas.

Cargo.toml
[package]
name = "addon-node"
version = "0.1.0"
edition = "2021"

[dependencies]
zyris = { git = "https://github.com/attacca-cc/zyris-protocol", features = ["caps", "tls-ring"] }
zyris-fs = { git = "https://github.com/attacca-cc/zyris-protocol" }
zyris-terminal = { git = "https://github.com/attacca-cc/zyris-protocol" }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
src/main.rs
use zyris::caps::{FileIoServer, TerminalServer};
use zyris::{Node, NodeKind};
use zyris_fs::LocalFileIo;
use zyris_terminal::PtyTerminal;

#[zyris::capability(name = "health", version = 1)]
pub trait Health {
    /// Check whether this application is ready to serve requests.
    async fn status(&self) -> zyris::Result<String>;
}

struct AppHealth;

#[zyris::async_trait]
impl Health for AppHealth {
    async fn status(&self) -> zyris::Result<String> {
        Ok("ready".into())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = std::env::var("ZYRIS_CREDENTIAL")?;
    let root = std::env::current_dir()?;
    let link = Node::builder()
        .name("addon-node")
        .kind(NodeKind::Service)
        .capability(FileIoServer(LocalFileIo::rooted(root.clone())))
        .capability(TerminalServer(PtyTerminal::rooted(root)))
        .capability(HealthServer(AppHealth))
        .build()?
        .connect(zyris::DEFAULT_SERVER_URL, &credential)
        .await?;

    tokio::select! {
        closed = link.wait_closed() => closed?,
        _ = tokio::signal::ctrl_c() => link.disconnect().await,
    }
    Ok(())
}

Run from the directory relative paths should start in. Supply a stored credential, or adapt the quickstart enrollment flow for first-run registration. Never commit the credential.

A root directory is not a sandbox

LocalFileIo::rooted and PtyTerminal::rooted establish defaults for relative paths. Absolute paths and .. can leave the root, and a shell can access anything its operating-system user can. Enforce authorization and isolation before exposing these tools to untrusted callers.

Desktop addons

Serve screenshot and input capabilities together when an agent needs to see and act on a desktop. Pass HostDisplays(capture.backend()) from zyris-screen to EnigoInput::new(..) so both use the same backend, including an explicit capture override. Input initialization can fail on a headless host; do not announce an unusable backend.

HostScreenCapture supports with_format and with_max_width. When screenshots are downscaled, their descriptions identify the coordinate conversion needed before calling input. Do not apply Display::scale_factor a second time.

Addon / featureHost requirements
zyris-screenDisplay development libraries on Linux. Uses wlroots capture where available, otherwise xcap; Wayland portal support matters.
zyris-inputlibxkbcommon on Linux; Accessibility permission on macOS. Default Linux input uses XTEST.
zyris-input/waylandwlroots virtual keyboard/pointer protocols and Wayland development libraries.
zyris-input/libeiGNOME/KDE RemoteDesktop portal support and a user permission grant.

The current libei input backend has a fractional-scaling limitation. Screen capture also documents multi-monitor and rotation limitations. Read the maintained screen README and input README for your target platform. Keep display dependencies out of headless services that do not need them.

File-transfer addons

zyris-transfer separates filesystem handling from the heavier peer transport:

FeatureWhat it adds
No optional featuresReceiving state, inbox handling, resumable transfers, audit records and replacement undo storage.
sendPeer discovery, key pinning and dialing for file_transfer.send_to.
listenAccepting and identifying incoming peer connections.

send and listen are independent and off by default. Both pull in zyris-p2p and iroh, which can introduce a TLS C build. Registering a receiving implementation does not itself start a listener or configure discovery; follow the transfer documentation when wiring those pieces together.

Receiving has its own defenses: names are reduced to one component, destination paths are checked for symlinks, the per-file size limit applies, and existing files are moved aside before replacement. The current max_inbox_bytes field is not enforced, and audit logging defaults to off. Configure storage quotas and audit locations yourself. See the transfer guide for the separate incoming/outgoing trust rules; these checks are not a host-wide sandbox.

Extend without starting from zero

  1. Compose. Add a domain-specific trait with #[zyris::capability] and register its generated server beside the addons, as the Health example does.
  2. Replace. Implement a standard trait yourself—for example, FileIo backed by object storage—and use the same generated server wrapper. Callers retain the standard typed client.
  3. Wrap. Put application policy in front of an addon, delegate allowed operations and reject others. Cover streaming methods as well as unary methods; guarding only read leaves other paths open.

Preserve the standard tool contract when replacing an implementation. Use a new capability name or version for incompatible arguments or behavior, and register the replacement instead of the original. Writing capabilities covers schemas, errors, streaming and versioning.

Migrate from zyris-capkit

zyris-capkit is a git-only compatibility facade, not the recommended dependency for new code. Its implementations have moved into individual crates:

Old importNew import
zyris_capkit::LocalFileIozyris_fs::LocalFileIo
zyris_capkit::PtyTerminalzyris_terminal::PtyTerminal
zyris_capkit::{HostScreenCapture, HostDisplays, ScreenBackend}zyris_screen::{HostScreenCapture, HostDisplays, ScreenBackend}
zyris_capkit::{EnigoInput, settings_for_session}zyris_input::{EnigoInput, settings_for_session}
zyris_capkit::transfer::*zyris_transfer::*
zyris_capkit::{Displays, resolve_under}zyris_caps::{Displays, resolve_under}

Move dependencies and imports together. Facade features transfer-send and input-libei become zyris-transfer's send and zyris-input's libei. Add only the crates and features you use. The facade is intended to disappear after its existing consumers migrate.

Source and API reference

On this page