Skip to main content

recall_wire/
lib.rs

1//! The contract between Recall's client and server: request and response
2//! shapes, and the validation rules that apply to both.
3//!
4//! Keeping this in one crate is the point of a workspace rather than two
5//! programs. Before the implementations were unified, `file_path`
6//! validation and the tombstone/empty-file distinction existed twice — in
7//! JavaScript on the server and in bash on the client — with nothing
8//! keeping them in agreement, so a drift between them would only surface in
9//! production.
10//!
11//! # Layout
12//!
13//! One module per endpoint, since that is the unit that has to stay
14//! compatible. Every type is also re-exported at the crate root, so callers
15//! can write `recall_wire::PushRequest` and never think about which endpoint
16//! a type belongs to.
17//!
18//! | Module | Endpoint |
19//! |---|---|
20//! | [`sync`] | `POST /sync`, `GET /sync` — memory files in both directions |
21//! | [`health`] | `GET /health` — unauthenticated liveness and merge status |
22//! | [`admin`] | `GET /admin/stats` — what is stored, per project |
23//! | [`validate`] | the rules both halves enforce |
24//!
25//! # Frozen surface
26//!
27//! **These JSON shapes are frozen.** The deployed Node server speaks them,
28//! its SQLite rows were written against them, and during any migration a
29//! machine on the old client and one on the new binary talk to the same
30//! deployment. Field names and ordering here are compatibility surface, not
31//! style.
32//!
33//! That includes timestamps, which every `updated_at`, `checked_at` and
34//! `last_*_at` field carries as JavaScript's `Date.toISOString()` —
35//! millisecond precision with a `Z` suffix, e.g. `2026-09-03T21:49:55.191Z`.
36//! Rows already in the database are in that shape. `recall_server::now`
37//! produces it.
38//!
39//! The full reference, including status codes and worked `curl` examples,
40//! is in `docs/reference/api.md`.
41
42#![deny(missing_docs)]
43
44pub mod admin;
45pub mod health;
46pub mod sync;
47pub mod validate;
48
49pub use admin::{AdminStats, AdminTotals, ProjectStats};
50pub use health::{ClaudeCliStatus, Health, MergeError, MergeStatus};
51pub use sync::{File, PushRequest, PushResponse, SyncResponse};
52pub use validate::{validate_file_path, ValidationError};
53
54use serde::{Deserialize, Serialize};
55
56/// Body returned for any non-2xx, on every endpoint.
57///
58/// It lives at the root rather than in an endpoint module because it belongs
59/// to all of them: whatever a request was trying to do, this is the shape of
60/// being told no.
61#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
62pub struct ErrorResponse {
63    /// A human-readable reason, safe to show a user.
64    pub error: String,
65}