Skip to main content

ws-ckpt IPC Protocol

Overview

cosh-ng communicates with the ws-ckpt daemon via Unix Domain Socket to manage workspace snapshots. Communication uses a frame format of bincode serialization + 4-byte little-endian length prefix.

Architecture

cosh-cli / cosh-core ws-ckpt daemon
│ │
│ Unix socket │
│ /run/ws-ckpt/ws-ckpt.sock │
│─────────────────────────────→│
│ [4B LE len][bincode req] │
│ │
│←─────────────────────────────│
│ [4B LE len][bincode resp] │

The client implementation is in crates/cosh-platform/src/checkpoint.rs (CkptClient), and type definitions are in crates/cosh-types/src/checkpoint.rs.

Frame Format

Each message consists of two parts:

┌──────────────────┬───────────────────────────────┐
│ 4-byte LE u32 │ bincode-encoded enum payload │
│ (payload length) │ (WsCkptRequest / Response) │
└──────────────────┴───────────────────────────────┘
  • Length prefix: little-endian unsigned 32-bit integer representing the byte count of the subsequent bincode payload
  • Maximum response limit: 64 MiB (prevents OOM)
  • Default timeout: 5000ms (configurable via CkptClient::with_timeout())

Request Types (WsCkptRequest)

bincode serializes enums by variant index (first variant = index 0). Variant order is the binary contract and must not be reordered.

IndexVariantDescription
0Init { workspace }Initialize a workspace
1Checkpoint { workspace, id, message, metadata, pin }Create a snapshot
2Rollback { workspace, to }Rollback to a specified snapshot
3Delete { workspace, snapshot, force }Delete a snapshot
4List { workspace, format }List snapshots
5Diff { workspace, from, to }Diff between two snapshots
6Status { workspace }Query status
7Cleanup { workspace, keep }Clean up old snapshots
8ConfigGet daemon configuration
9ReloadConfigReload configuration
10Recover { workspace }Recover a workspace
11HealthAdvisoryHealth check

Response Types (WsCkptResponse)

VariantCorresponding RequestKey Fields
InitOk { ws_id }InitWorkspace ID
CheckpointOk { snapshot_id }CheckpointSnapshot ID
RollbackOk { from, to }RollbackRollback source and target
DeleteOk { target }DeleteDeleted snapshot identifier
Error { code, message }AnyError code + human-readable description
ListOk { snapshots }ListVec<SnapshotEntry>
DiffOk { changes }DiffVec<DiffEntry>
StatusOk { report }StatusStatusReport
CleanupOk { removed }CleanupList of removed snapshot IDs
ConfigOk { config }ConfigConfigReport
ReloadConfigOkReloadConfigNo payload
CheckpointSkipped { reason }CheckpointSkip reason (e.g., no changes)
RecoverOk { workspace }RecoverRecovered workspace path
HealthAdvisoryOk { ... }HealthAdvisoryOver-limit workspace count, disk usage

Error Codes (WsCkptErrorCode)

IndexVariantDescription
0WorkspaceNotFoundWorkspace does not exist
1SnapshotNotFoundSnapshot does not exist
2AlreadyInitializedWorkspace already initialized
3BtrfsErrorBtrfs operation error
4IoErrorI/O error
5InvalidPathInvalid path
6ConfirmationRequiredConfirmation needed (e.g., deleting a pinned snapshot)
7InternalErrorInternal error
8SnapshotAlreadyExistsSnapshot ID conflict
9WriteLockConflictWrite lock conflict
10DiskSpaceInsufficientInsufficient disk space

Client Usage

use cosh_platform::checkpoint::CkptClient;

// Default path /run/ws-ckpt/ws-ckpt.sock
let client = CkptClient::default_path();

// Or specify path and timeout
let client = CkptClient::with_timeout("/custom/path.sock", 10000);

// Health check
if !client.is_available() {
eprintln!("ws-ckpt daemon not running");
}

// Operation examples
let result = client.create("/home/user/project", "snap-001", Some("initial"), None, false)?;
let list = client.list(Some("/home/user/project"))?;
let restored = client.restore("/home/user/project", "snap-001")?;

Key Constraints

ConstraintDescription
Variant order is immutablebincode serializes enums by index; reordering breaks the wire format
New additions append onlyNew Request/Response variants can only be added at the end
Types must stay in syncDefinitions in cosh-types must exactly match ws-ckpt-common
Timeout handlingClient sets read/write timeouts to avoid blocking when daemon is unresponsive
Length limitResponses exceeding 64 MiB are treated as anomalous; connection is dropped immediately
Socket pathDefault /run/ws-ckpt/ws-ckpt.sock; overridable via environment variable or CLI argument

Test Verification

cd src/cosh-ng

# bincode round-trip serialization tests
cargo test --locked -p cosh-types -- checkpoint

# Variant index contract tests
cargo test --locked -p cosh-types test_request_bincode_variant_index

# CkptClient unit tests (no running daemon required)
cargo test --locked -p cosh-platform -- checkpoint