Skip to content
robolibsPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

agentio

agentio is a Rust library for composing authenticated peerbus endpoints by topic name. One Agent owns one peerbus::Node, one Ed25519 identity, a local directory, and its control-plane workers. A multi-machine composition consists of several Agents that exchange signed directory records.

Model

  • A Machine is one endpoint identity and its peerbus::Node.
  • An Agent is the owning handle for that Machine's IO and directory state.
  • A topic is a normalized absolute path such as /perception/pose.
  • qualify_participant_topic and subscribe_in provide local topic-prefix convenience. There is no participant registry or participant discovery.

Each hosted exchange is recorded with its topic, exchange family, request and response type hashes, owner endpoint, revision, lease expiry, machine name, and owner signature. Received announcements and snapshots are verified before insertion. Older revisions, expired records, invalid signatures, type mismatches, and competing live owners are rejected. Hosted records are renewed; dropping the returned Registered publisher/server handle sends a signed withdrawal bound to the exact signed record it removes. Startup and periodic reconciliation recover missed announcements; reconcile_now also triggers it on demand. Snapshot pages carry a generation number, so a mutation during pagination restarts the snapshot instead of mixing two directory states.

Membership and authorization

Discovery and authorization are separate:

  • bootstrap([...]) configures outbound directory seeds only.
  • allow_peer(id) and allow_peers([...]) configure inbound transport access.
  • allow_any_peer() explicitly opts out of the deny-by-default allowlist.
  • DirectoryMode::Replicated reconciles every configured seed.
  • DirectoryMode::FrontDoor(id) uses one directory authority. The front-door ID is not automatically authorized for inbound transport.

For production, exchange endpoint IDs through a trusted channel and use explicit allowlists. allow_any_peer is appropriate only for a deliberately permissive trust boundary. An ALPN identifies a protocol; it is not a secret or an authorization mechanism.

Resolution and transport

A typed client first checks its verified local directory and can query a seed's reserved __agentio_resolve req/res service. It validates the returned topic, exchange family, and type hashes before dialing the owner directly. by_id bypasses directory resolution but not peerbus transport authorization.

Each configured directory target has one bounded worker and one persistent control client. Unreachable seeds therefore do not serialize calls to healthy seeds. control_timeout bounds the caller-visible wait; the target worker may still be completing the underlying peerbus call. lease_duration controls record expiry and the automatic renewal cadence. The defaults are six seconds for control calls and 30 seconds for leases.

Peerbus can use shared memory for co-located endpoints and iroh QUIC for remote endpoints. skip_shm() forces QUIC; no_relay() disables relay fallback. wait_for_direct_addresses provides bounded address readiness for remote setups. Rust transport type hashes include the Rust type path, so separate binaries must import shared message definitions from the same crate. The heavy and camera examples use the small examples/shared_types support crate for this reason.

Identities

IdentitySource::Random creates a non-persistent identity. Named, default, DID, and explicit-file sources persist 32-byte keys with owner-only Unix permissions and fail on malformed or insecure existing files. DID-index copy failures are returned to the caller. A human-readable name is never converted into private key material. See docs/migrations/identity-derived-name.md when migrating from the removed name-derived API.

Minimal example

use agentio::{Agent, IdentitySource};
use datapod::datapod;
use std::time::Duration;

#[datapod]
struct Pose {
    x: f32,
    y: f32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let agent = Agent::builder()
        .identity(IdentitySource::Random)
        .name("local")
        .build()?;
    let mut publisher = agent.publish::<Pose>("/pose")?;
    let mut subscriber = agent.subscribe::<Pose>("/pose")?;

    publisher.send(&Pose { x: 1.0, y: 2.0 })?;
    let sample = subscriber
        .recv_timeout(Duration::from_secs(1))?
        .ok_or("pose timed out")?;
    assert_eq!(sample.header().x, 1.0);
    Ok(())
}

Lifecycle and health

Agent clones share one inner node. Dropping a non-final clone changes nothing; dropping the final clone signals and joins both control workers before the node is released. Publisher and server wrappers withdraw their records on drop while the Agent remains live.

directory_health() snapshots announcement successes/failures, resolver errors, rejected records, last successful reconciliation, stale seed count, conflicts, and pending announcements. Configuration, signature, expiry, ownership, exchange, type, batch, and stale-revision failures are typed Error variants.

Commands

The Makefile is the supported command surface:

make run
make run EXAMPLE=05_all_exchanges
make run EXAMPLE=07_client_all ARGS='<SERVER_DID_KEY>'
make integration
make agent-test
make directory-test
make remote-test
make examples-smoke
make verify

Camera stream example

Examples 10/11 publish RGB frames from a Linux V4L2 camera and subscribe from a second Agent. They use GStreamer for camera capture and optional display, while the frame payload travels through agentio over iroh by default.

# Terminal 1: copy the printed did:key value
make camera-publisher CAMERA_DEVICE=/dev/video0

# Terminal 2: receive frames and open a display window
make camera-subscriber SERVER='<PUBLISHER_DID_KEY>' ARGS='--display'

Pass ARGS='--frames 30' for a bounded headless receiver, or ARGS='--use-shm' to either target when shared-memory transport is desired. Camera access requires read/write permission on the selected /dev/video* device. ARGS='--test-pattern' on the publisher replaces the camera with a GStreamer test pattern for transport testing.

Examples 06/07 are the two-process exchange demos. Examples 08/09 are bounded on every remote-controlled allocation and are throughput demos that measure actual received payload bytes and validate their content; they are not repeatable statistical benchmarks.

agentio is library-only. CI builds, tests, lints, and documents the library; it does not package a nonexistent application binary. Source releases remain a manual maintainer operation.

The audit target explicitly reports but does not block on RUSTSEC-2023-0071, a medium-severity timing advisory in rsa with no fixed release. Agentio's directory protocol uses Ed25519, not RSA. Applications that use RSA through the re-exported authbox surface must assess that advisory for their own threat model. The current dependency graph also produces a non-vulnerability maintenance warning for transitive paste 1.0.15 through iroh's networking stack.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages