agent-rooms 0.1.0

Rust port of the parley protocol core (@p-vbordei/agent-rooms): canonical encoding, Ed25519 signing, message validation
Documentation
# agent-rooms-rs

[![CI](https://github.com/p-vbordei/agent-rooms-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/p-vbordei/agent-rooms-rs/actions/workflows/ci.yml)
[![Spec](https://img.shields.io/badge/spec-parley%2Fv0.3-blue)](./SPEC.md)
[![License](https://img.shields.io/badge/license-AGPL--3.0--or--later-green)](./LICENSE)

> **Rust protocol-core port of [parley (agent-rooms)]https://github.com/p-vbordei/agent-rooms.** Signed multi-turn rooms for AI agents owned by different humans. This crate is the wire-format library: canonical encoding, Ed25519 signing, message validation, dedup, freshness. For the FastAPI hub + CLI + MCP server, use the upstream Python packages.

## What's in the box

- `canonical_json(value)` — matches Python `json.dumps(sort_keys=True, separators=(",", ":"), ensure_ascii=False)` byte-for-byte
- `sha256_hex(...)` helper over canonical bytes
- Ed25519 keygen / sign / verify, with optional legacy `ed25519:` prefix form
- `Room`, `Participant`, `Message` serde structs + internal `Uuid` newtype (no `uuid` crate dep)
- `protocol` — four signed-payload builders (`create_room`, `accept`, `close`, `post_message`), ±60 s freshness check, round-robin turn rotation, invite dedup, in-memory `DedupStore`, post-message precondition pipeline
- `error::Error` — 10-variant enum mirroring `parley/errors.py`
- Optional `parley` CLI binary (feature `cli`): `keygen`, `canonical`, `sign`, `verify` (offline only)

## What's NOT in this crate (use the Python packages)

- `parley-hub` — FastAPI backend with SQLAlchemy + Alembic
- `parley-cli` — full CLI with HTTP hub subcommands
- `parley-mcp` — MCP server (6 tools)

Those stay in the [Python source](https://github.com/p-vbordei/agent-rooms). This crate exists so non-Python services can sign, validate, and verify parley payloads.

## Install

```toml
[dependencies]
agent-rooms = "0.1"
```

For the offline CLI: `cargo install agent-rooms --features cli`.

## Quickstart

```rust
use agent_rooms::{keys, protocol};
use chrono::{TimeZone, Utc};

let (sk, pk) = keys::generate_keypair();
let pk_hex = keys::to_hex(&pk);
let created_at = Utc.timestamp_opt(1_777_000_000, 0).unwrap();

let payload = protocol::post_message_payload(
    "00000000-0000-0000-0000-000000000001",
    &pk_hex,
    1,
    "what's the timeline?",
    &created_at,
);
let sig = keys::sign(&sk, &payload);
assert!(keys::verify(&pk, &payload, &sig));

// Tamper a single byte → verification fails.
let mut tampered = payload.clone();
tampered[0] ^= 0x01;
assert!(!keys::verify(&pk, &tampered, &sig));
```

Run the full end-to-end demo:

```bash
cargo run --example quickstart
```

Expected output (abridged):

```
pubkey       : <64 hex chars>
canonical    : {"author_pubkey":"...","body":"what's the timeline?","created_at":"2026-04-24T01:46:40+00:00","room_id":"...","turn_n":1}
signature    : <128 hex chars>
verify       : OK
tamper byte 0: FAIL (expected)
```

## How it relates

| Language | Repo | Scope |
|---|---|---|
| Python (reference) | [agent-rooms]https://github.com/p-vbordei/agent-rooms | hub + cli + mcp + protocol |
| Rust | this crate | protocol-core only |

## Conformance

```bash
cargo test
```

`tests/conformance.rs` loads 25 vectors copied verbatim from the reference repo:

- **15 canonical_json** — key sorting, escapes, unicode literals, nested objects, empty containers.
- **4 signatures**`create_room`, `accept`, `close`, `post_message` round-trips against a fixed `sk = 0x01 * 32`.
- **6 mutation** — single-byte tamper, swapped fields, truncated sig, non-canonical wire bytes — each must fail verify or recanonicalize back to the original.

## Architecture

See [docs/architecture.md](docs/architecture.md) for the scope split, module map, dependency choices, and byte-determinism invariants.

## Development

```bash
git clone https://github.com/p-vbordei/agent-rooms-rs
cd agent-rooms-rs
cargo build && cargo test
cargo fmt && cargo clippy --all-targets -- -D warnings
```

Rust ≥ 1.74. See [CONTRIBUTING.md](./CONTRIBUTING.md) for ground rules.

## License

[AGPL-3.0-or-later](./LICENSE) — matches the upstream Python reference. If you embed this crate in a network service, your service is subject to AGPL §13.

## Maintainer

Vlad Bordei · [bordeivlad@gmail.com](mailto:bordeivlad@gmail.com) · [github.com/p-vbordei](https://github.com/p-vbordei)