feat(agent): add ssh_scheduler + update README with diff, SshSyncBackend, test count

- ssh_scheduler() convenience constructor mirrors tcp_scheduler for SSH backend
- Re-exported from clawsync_agent crate root
- README: diff command section, SshSyncBackend library usage table + example,
  updated crate interdependency description, test count 617→644

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
osobh
2026-04-06 10:22:28 -05:00
co-authored by Claude Sonnet 4.6
parent 11f946a608
commit 40994eaabe
3 changed files with 101 additions and 5 deletions
+74 -3
View File
@@ -163,7 +163,7 @@ crates/
clawsync-onion/ Packet differ/merger, IBLT sketch, Merkle tree, ClawSyncManifest clawsync-onion/ Packet differ/merger, IBLT sketch, Merkle tree, ClawSyncManifest
clawsync-hdf5/ Dataset-level manifest, differ, patcher (HDF5-aware sync) clawsync-hdf5/ Dataset-level manifest, differ, patcher (HDF5-aware sync)
clawsync-transport/ TCP, QUIC (quinn 0.11/TLS 1.3), length-prefixed wire protocol clawsync-transport/ TCP, QUIC (quinn 0.11/TLS 1.3), length-prefixed wire protocol
clawsync-agent/ OnionMemory, SyncScheduler, TcpSyncBackend, capability negotiation clawsync-agent/ OnionMemory, SyncScheduler, TcpSyncBackend/QuicSyncBackend/SshSyncBackend
clawsync-fs/ CDC-based delta sync for any file type (FsSyncClient, FsSyncServer) clawsync-fs/ CDC-based delta sync for any file type (FsSyncClient, FsSyncServer)
clawsync-cli/ clawsync binary — all commands wired here clawsync-cli/ clawsync binary — all commands wired here
``` ```
@@ -193,7 +193,7 @@ The workspace `.cargo/config.toml` sets `target-cpu=native` for SIMD throughput
### Run tests ### Run tests
```bash ```bash
cargo test --workspace # ~573 tests cargo test --workspace # ~644 tests
cargo test --workspace --features simd-cdc # +16 SIMD CDC tests cargo test --workspace --features simd-cdc # +16 SIMD CDC tests
cargo bench -p clawhdf5-onion # Criterion benchmarks cargo bench -p clawhdf5-onion # Criterion benchmarks
``` ```
@@ -642,6 +642,33 @@ clawsync branch merge model.h5 experiment --into main --strategy latest-wins
--- ---
### diff
Show page-level differences between two revisions of a local `.onion` sidecar. If `REV2` is omitted, compares `REV1` against the current HEAD.
```bash
clawsync diff <LOCAL.h5> <REV1> [REV2] [--porcelain]
```
```bash
clawsync diff model.h5 5 8
# Diff rev 5 → rev 8:
# ~ page 0 (changed, 4096 B)
# + page 12 (added, 4096 B)
# - page 7 (removed)
# 1 page(s) changed, 1 added, 1 removed.
# Machine-readable output
clawsync diff model.h5 5 8 --porcelain
# ~ 0 4096
# + 12 4096
# - 7
```
Detection is based on `data_offset` equality in the append-only sidecar: two revisions referencing the same offset contain identical bytes, so a changed entry is unambiguous without decompressing any page data.
---
## Transport: TCP, QUIC, and SSH ## Transport: TCP, QUIC, and SSH
All network commands support TCP (default), QUIC (`--quic`), and SSH (automatic when the remote address contains `@`). All network commands support TCP (default), QUIC (`--quic`), and SSH (automatic when the remote address contains `@`).
@@ -774,7 +801,7 @@ cargo build --workspace --release
### Testing ### Testing
```bash ```bash
# All tests (~617 default, ~633 with SIMD CDC) # All tests (~644 default, ~660 with SIMD CDC)
cargo test --workspace cargo test --workspace
cargo test --workspace --features simd-cdc cargo test --workspace --features simd-cdc
@@ -809,6 +836,50 @@ clawsync-cli
└── clawsync-core (BLAKE3, xxHash3, FastCDC, zstd) └── clawsync-core (BLAKE3, xxHash3, FastCDC, zstd)
``` ```
### Using `clawsync-agent` as a library
The `clawsync-agent` crate exposes a `SyncBackend` trait with three implementations:
| Backend | When to use |
|---------|-------------|
| `TcpSyncBackend` | Pre-running `clawsync serve` on LAN |
| `QuicSyncBackend` | Encrypted WAN, pre-running `clawsync serve --quic` |
| `SshSyncBackend` | No pre-running server; spawns `clawsync serve --stdio` on demand |
```rust
use clawsync_agent::{SshSyncBackend, SyncBackend, ssh_scheduler};
use clawsync_agent::{TcpSyncBackend, tcp_scheduler};
use clawsync_onion::selector::SyncSelector;
// SSH — no daemon needed
let scheduler = ssh_scheduler(
"[email protected]",
"/data/agent.claws",
local_h5_path,
"my-agent",
SyncSelector::All,
);
// TCP — pre-running serve required
let scheduler = tcp_scheduler(
"127.0.0.1:9999",
local_h5_path,
"my-agent",
SyncSelector::All,
)?;
// Drive the scheduler manually
let stats = scheduler.sync_once().await?;
// Or hook into OnionMemory for autonomous post-flush sync
use clawsync_agent::OnionMemory;
let backend = SshSyncBackend::new("user@host", "/remote/agent.claws", "agent-1");
let memory = OnionMemory::new(local_h5_path, backend);
memory.record_and_flush(data).await?;
```
Override the SSH binary (e.g. for testing) by setting `CLAWSYNC_SSH_COMMAND` or calling `.with_ssh_command(path)` on the backend.
### Wire protocol stability ### Wire protocol stability
`SyncMessage` variants are serialized with rkyv and assigned discriminants positionally. **Never insert or reorder variants** — always append. The current variant list: `SyncMessage` variants are serialized with rkyv and assigned discriminants positionally. **Never insert or reorder variants** — always append. The current variant list:
+2 -2
View File
@@ -3,7 +3,7 @@
//! //!
//! ## Modules //! ## Modules
//! //!
//! - [`backend`]: `SyncBackend` trait + `TcpSyncBackend` / `QuicSyncBackend` implementations //! - [`backend`]: `SyncBackend` trait + `TcpSyncBackend` / `QuicSyncBackend` / `SshSyncBackend`
//! - [`onion_memory`]: `OnionMemory` — revision-aware wrapper around `HDF5Memory` //! - [`onion_memory`]: `OnionMemory` — revision-aware wrapper around `HDF5Memory`
//! - [`scheduler`]: `SyncScheduler` — autonomous push after each flush //! - [`scheduler`]: `SyncScheduler` — autonomous push after each flush
//! - [`negotiator`]: Peer capability negotiation //! - [`negotiator`]: Peer capability negotiation
@@ -38,4 +38,4 @@ pub use backend::{
pub use error::AgentSyncError; pub use error::AgentSyncError;
pub use negotiator::{SessionCapabilities, assert_compatible, negotiate}; pub use negotiator::{SessionCapabilities, assert_compatible, negotiate};
pub use onion_memory::{MemorySnapshot, OnionMemory}; pub use onion_memory::{MemorySnapshot, OnionMemory};
pub use scheduler::{SyncScheduler, tcp_scheduler}; pub use scheduler::{SyncScheduler, ssh_scheduler, tcp_scheduler};
+25
View File
@@ -103,6 +103,31 @@ pub fn tcp_scheduler(
)) ))
} }
/// Convenience constructor: create a [`SyncScheduler`] backed by
/// [`SshSyncBackend`].
///
/// - `user_host` — SSH target, e.g. `"[email protected]"`
/// - `remote_path` — absolute path on the remote, e.g. `"/data/agent.claws"`
/// - `h5_path` — local HDF5 file to sync
/// - `agent_id` — identifier sent in protocol messages
/// - `selector` — which revisions to push
///
/// The `CLAWSYNC_SSH_COMMAND` environment variable overrides the SSH binary
/// (defaults to `ssh`).
pub fn ssh_scheduler(
user_host: &str,
remote_path: &str,
h5_path: PathBuf,
agent_id: &str,
selector: SyncSelector,
) -> SyncScheduler<crate::backend::SshSyncBackend> {
SyncScheduler::new(
crate::backend::SshSyncBackend::new(user_host, remote_path, agent_id),
h5_path,
selector,
)
}
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
// Tests // Tests
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────