agent-scroll 0.1.0

Canonical byte-deterministic transcript format for AI-agent conversations (Rust port of @p-vbordei/agent-scroll)
Documentation
# agent-scroll (Rust)

[![CI](https://github.com/p-vbordei/agent-scroll-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/p-vbordei/agent-scroll-rs/actions/workflows/ci.yml)
[![Spec](https://img.shields.io/badge/spec-v0.1-blue)](./SPEC.md)
[![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)

> **Idiomatic Rust port of [`@p-vbordei/agent-scroll`]https://github.com/p-vbordei/agent-scroll.** Canonical byte-deterministic transcript format for AI-agent conversations. Same RFC 8785 JCS bytes, same SHA-256 hashes, same Ed25519 signatures as the TypeScript reference — verified by 20 byte-equality vectors plus mutation, roundtrip, and chain-tamper tests.

A scroll is an ordered chain of *sealed turns*. Each turn is a normalized `serde_json::Value` (`{version, turn, role, model, params, messages, ..., timestamp_ns, prev_hash?}`) serialized via JCS, SHA-256 hashed, optionally Ed25519-signed, and linked to its predecessor by `prev_hash`. Any byte flip — in body, hash, signature, or chain order — is detectable.

## What's in the box

- `canonical(&Value)` — RFC 8785 JCS bytes (with a `u64 → f64` normalization pass; see [Architecture]docs/architecture.md)
- `hash_canonical(&Value)``sha256:<hex>` string
- `seal(&turn, sign)` — produce a sealed `Value` (hash + optional Ed25519 signature)
- `seal_chain(&[Value], sign)` — chain-linked sealed turns, each carrying `prev_hash`
- `verify(&[Value], pubkey)` — schema + hash + chain link + signature
- `serialize` / `deserialize` — round-trip via canonical bytes
- `validate_turn` / `validate_sealed_turn` — explicit role / tool-call schema checks

## Install

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

## Quickstart

See [`examples/quickstart.rs`](examples/quickstart.rs). Build three turns, seal-and-sign as a chain, verify, then mutate a byte and watch verify fail:

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

Expected output:

```
sealed 3 turns, all hashes set
verify clean: ok=true
verify tampered: ok=false reason=BadHash
```

## How it relates

| Port | Source | Same vectors |
|---|---|---|
| [`agent-scroll`]https://github.com/p-vbordei/agent-scroll | TypeScript reference ||
| [`agent-scroll`]https://pypi.org/project/agent-scroll/ | Python | C1–C4 + 20 byte-equality |
| [`agent-scroll`]https://crates.io/crates/agent-scroll (this repo) | Rust | C1–C4 + 20 byte-equality |

## Conformance

This port is verified against the same fixture set as the TypeScript reference:

- **C1** — byte equality across 20 vectors (the gold standard). Canonical bytes of each fixture must hex-match the TS output.
- **C2** — single-byte mutation in hash or body MUST fail `verify`.
- **C3**`serialize``deserialize` roundtrip is byte-stable.
- **C4** — chain tamper / reorder MUST fail `verify`.

```bash
cargo test
```

Fixtures in [`fixtures/`](fixtures/) (`c1-hex.json` carries the expected hex per vector) and the 20 wire-format vectors in [`vectors/`](vectors/) are copied verbatim from the [TS conformance suite](https://github.com/p-vbordei/agent-scroll/tree/main/conformance).

## Architecture

See [`docs/architecture.md`](docs/architecture.md) for module map, dependency choices, and the critical `serde_jcs` `u64`-precision workaround (`timestamp_ns` is a `u64` larger than `2^53`, which `serde_jcs` doesn't coerce to `f64` as RFC 8785 mandates — we normalize numbers manually in `canonical.rs`).

## Development

```bash
git clone https://github.com/p-vbordei/agent-scroll-rs
cd agent-scroll-rs
cargo test
cargo run --example quickstart
```

## License

Apache-2.0 — see [LICENSE](./LICENSE).