Suture Architecture v5.3.1 (Post-Audit)

System Overview

Suture is a patch-based version control system with semantic merge capabilities. It understands the structure of files (JSON, YAML, CSV, XML, DOCX, XLSX, PPTX, OTIO, SQL, PDF, images, and more) and merges them intelligently using format-aware drivers rather than treating them as opaque text.

High-Level Component Diagram


                           User Interface Layer
    ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
    │suture-cli│  │suture-tui│  │suture-lsp│  │ VS Code  │  │ Tauri    │
    │(clap, 58 │  │(ratatui, │  │(tower-   │  │Extension │  │Desktop   │
    │ commands)│  │ 7 tabs)  │  │ lsp)     │  │(TS)      │  │(HTML UI) │
    └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘
         │              │              │              │              │
         └──────────────┴──────┬───────┴──────────────┘              │
                               │                                     │
              ┌────────────────┼────────────────┐                     │
              │                │                │                     │
       ┌──────▼──────┐ ┌──────▼──────┐ ┌───────▼───────┐             │
       │ suture-core │ │suture-driver │ │suture-protocol│             │
       │ CAS, DAG,   │ │ trait +      │ │ wire format,  │             │
       │ patches,    │ │ registry     │ │ compression   │             │
       │ repo engine │         │ (18 drivers) │ │ delta encoding│             │
       └──────┬──────┘ └──────┬──────┘ └───────┬───────┘             │
              │               │                │                     │
       ┌──────▼──────┐       │                │                     │
       │suture-common│       │                │                     │
       │Hash, types  │       │                │                     │
       └─────────────┘       │                │                     │
              ┌──────────────┼────────────────┘                     │
              │              │                                      │
    ┌─────────▼─────────┐   │         ┌─────────────────────┐      │
    │  suture-platform  │   │         │    suture-hub       │◄─────┘
    │  Web UI, auth,    │   │         │ HTTP/gRPC server,  │
    │  billing, merge   │   │         │ SQLite, auth,       │
    │  API, orgs        │   │         │ webhooks, mirrors   │
    └─────────┬─────────┘   │         └──────────┬──────────┘
              │              │                    │
    ┌─────────▼─────────┐   │         ┌──────────▼──────────┐
    │  Stripe           │   │         │  suture-raft        │
    │  billing          │   │         │  consensus, election│
    │  webhooks         │   │         │  log replication    │
    └───────────────────┘   │         └──────────┬──────────┘
                            │                    │
         ┌──────────────────┼────────────────────┘
         │                  │
  ┌──────▼──────┐   ┌──────▼──────┐
  │ suture-s3   │   │suture-daemon│
  │ blob store  │   │ file watch, │
  │ AWS SigV4   │   │ auto-sync,  │
  │ MinIO compat│   │ SHM, FUSE   │
  └─────────────┘   └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │ suture-vfs  │
                    │ FUSE3 mount │
                    │ WebDAV      │
                    └─────────────┘

Data Flow: Merge Request Through the System


 1. User edits files          2. suture add / commit
 ┌─────────────┐              ┌──────────────────┐
 │ Working     │──────────────▶│ Stage changes    │
 │ Tree        │              │ Create patch     │
 └─────────────┘              │ (BLAKE3 hash)    │
                              └────────┬─────────┘
                                       │
 3. Patch stored in CAS               ▼
 ┌──────────────────┐       ┌──────────────────┐
 │ BlobStore        │◀──────│ PatchDag         │
 │ .suture/objects/ │       │ Add node + edges │
 │ (content-addrs)  │       │ Acyclicity check │
 └──────────────────┘       └────────┬─────────┘
                                      │
 4. Push to remote (optional)        ▼
 ┌──────────────────┐       ┌──────────────────┐
 │ suture-hub       │◀──────│ suture-protocol  │
 │ HTTP/gRPC        │       │ Zstd compression │
 │ V2 handshake     │       │ Delta encoding   │
 └──────────────────┘       └──────────────────┘

 5. Merge
 ┌──────────────────┐
 │ suture merge     │
 │ feature-branch   │
 └────────┬─────────┘
          │
          ▼
 ┌──────────────────┐    ┌────────────────────┐
 │ Compute LCA      │───▶│ PatchDag::lca()    │
 │ (merge base)     │    │ Lowest Common      │
 │                  │    │ Ancestor            │
 └────────┬─────────┘    └────────────────────┘
          │
          ▼
 ┌──────────────────┐    ┌────────────────────┐
 │ Per-file merge   │───▶│ DriverRegistry     │
 │                  │    │ lookup by extension │
 └────────┬─────────┘    └────────────────────┘
          │
     ┌────┴────┐
     │         │
     ▼         ▼
 ┌───────┐ ┌───────┐
 │Driver │ │Text   │
 │exists?│ │merge  │
 │       │ │fallback│
 └───┬───┘ └───┬───┘
     │         │
     ▼         ▼
 ┌──────────────────┐
 │ Three-way merge  │
 │ driver.merge()   │
 │ or line-based    │
 └────────┬─────────┘
          │
     ┌────┴────┐
     │         │
     ▼         ▼
 ┌───────┐ ┌───────┐
 │Clean  │ │Conflict│
 │Merge  │ │Markers │
 └───────┘ └───────┘

Deployment Topologies

Standalone (CLI Only)


┌──────────────────────────────┐
│ User Machine                 │
│  ┌────────┐  ┌────────────┐  │
│  │suture  │──│ .suture/   │  │
│  │cli     │  │ objects/   │  │
│  │        │  │ metadata.db│  │
│  └────────┘  └────────────┘  │
└──────────────────────────────┘

No server required. All operations are local. 17 semantic drivers available.

Hub + Clients


┌──────────────┐     HTTP/gRPC      ┌──────────────────┐
│ Client A     │◀──────────────────▶│ suture-hub       │
│ (CLI/TUI)    │                    │ SQLite + Ed25519 │
└──────────────┘                    │ auth, webhooks   │
                                    └────────┬─────────┘
┌──────────────┐     HTTP/gRPC               │
│ Client B     │◀────────────────────────────┘
│ (CLI/TUI)    │
└──────────────┘

Optional: suture-s3 for blob storage (replaces SQLite blobs)
Optional: suture-raft for HA clustering (3+ nodes)

Full Platform (SaaS)


┌──────────────┐     HTTPS          ┌──────────────────┐
│ Client       │◀──────────────────▶│ suture-platform  │
│ (Web UI /    │                    │ Axum + SQLite    │
│  REST API)   │                    │ JWT auth, Stripe │
└──────────────┘                    │ billing, orgs    │
                                    └────────┬─────────┘
┌──────────────┐     HTTPS                  │
│ VS Code /    │◀───────────────────────────┘
│ JetBrains /  │
│ Neovim       │
└──────────────┘

Billing tiers: Free (100 merges/mo), Pro ($9/mo), Enterprise ($29/mo)
Analytics available on Pro+
WASM plugin uploads on Enterprise

Core Components

suture-common

Path: crates/suture-common/ Tests: 8

Foundation types shared across all crates. Zero dependencies.

TypeDescription HashBLAKE3 256-bit content hash (32 bytes, 64 hex chars) PatchIdAlias for Hash — identifies patches by content BranchNameValidated branch name (non-empty, no null bytes) RepoPathValidated repository path (rejects .., absolute paths, null bytes)

Key operations:

  • Hash::from_data(data) — compute BLAKE3 hash
  • Hash::from_hex(str) / to_hex() — hex encoding/decoding
  • Hash::ZERO — sentinel value (all zeros)

suture-core

Path: crates/suture-core/ Tests: 298 Depends on: suture-common

The core engine coordinating four subsystems:

SubsystemFileDescription BlobStoresrc/cas/Content-addressable storage on disk. 2-char prefix directory scheme (256 buckets). Optional Zstd compression (level 3). Deduplication by hash. PatchDagsrc/dag/graph.rsIn-memory DAG of patch history. Ancestor/descendant queries, LCA computation, branch management. Reconstructed from SQLite on Repository::open(). MetadataStoresrc/metadata/SQLite-backed persistent metadata. Stores patches, branches, configuration. Patch Enginesrc/repository/repo_impl.rsOrchestrates CAS, DAG, metadata. Handles commit, merge, stash, reset, cherry-pick, rebase, blame, reflog, notes, GC, fsck, squash.

Additional capabilities:

  • Audit Log (src/audit.rs): Append-only JSONL with BLAKE3 hash chaining. Each entry contains hash of previous entry. Optional Ed25519 signatures.
  • Signing (src/signing/): Ed25519 key generation, signing, verification for push operations.
  • File-type Detection: 14 file types with auto_detect_repo_type().
  • Semantic Diff Formatter: File-type-aware diff output with driver labels.
  • Supply Chain Integrity: Shannon entropy analysis, 13 risk indicators, XZ-style attack detection.
  • Conflict Classification: Categorize merge conflicts by type.
  • Stash/RM/MV/Notes/GC/fsck/Squash/Patch composition: Full VCS lifecycle.

suture-driver

Path: crates/suture-driver/ Tests: 8 Depends on: suture-core, suture-common

Defines the SutureDriver trait and driver registry:

pub trait SutureDriver: Send + Sync {
    fn name(&self) -> &str;
    fn supported_extensions(&self) -> &[&str];
    fn diff(&self, base: Option<&str>, new: &str) -> Result<Vec<SemanticChange>, DriverError>;
    fn format_diff(&self, base: Option<&str>, new: &str) -> Result<String, DriverError>;
    fn merge(&self, base: &str, ours: &str, theirs: &str) -> Result<Option<String>, DriverError>;
    fn diff_raw(&self, base: &[u8], new: &[u8]) -> Result<Vec<SemanticChange>, DriverError> { ... }
    fn merge_raw(&self, base: &[u8], ours: &[u8], theirs: &[u8]) -> Result<Option<Vec<u8>>, DriverError> { ... }
}
  • diff() / diff_raw() produce SemanticChange entries (Added, Removed, Modified, Moved)
  • merge() / merge_raw() return Some(merged) for clean merges, None for conflicts
  • format_diff() produces human-readable diff output

DriverRegistry (src/registry.rs): Dispatches to the correct driver by file extension. The CLI builds a builtin_registry() registering all 17 drivers.

SemanticChange types:

pub enum SemanticChange {
    Added { path: String, value: String },
    Removed { path: String, old_value: String },
    Modified { path: String, old_value: String, new_value: String },
    Moved { old_path: String, new_path: String, value: String },
}

Builtin Drivers (17)

DriverCrateExtensionsTests JSONsuture-driver-json.json47 YAMLsuture-driver-yaml.yaml, .yml30 TOMLsuture-driver-toml.toml30 CSVsuture-driver-csv.csv27 XMLsuture-driver-xml.xml31 Markdownsuture-driver-markdown.md, .markdown, .mdown, .mkd41 SQLsuture-driver-sql.sql18 DOCXsuture-driver-docx.docx13 XLSXsuture-driver-xlsx.xlsx13 PPTXsuture-driver-pptx.pptx19 OTIOsuture-driver-otio.otio21 PDFsuture-driver-pdf.pdf12 Imagesuture-driver-image.png, .jpg, .jpeg, .gif, .bmp, .webp, .tiff, .ico, .avif12 HTMLsuture-driver-html.html, .htm— SVGsuture-driver-svg.svg— Feedsuture-driver-feed.rss, .atom— iCalsuture-driver-ical.ics, .ifb

Supporting crate: suture-ooxml — shared OOXML infrastructure (ZIP parsing, part navigation, per-part relationship resolution).


suture-hub

Path: crates/suture-hub/ Tests: 61 (with features) Depends on: suture-common, suture-core, suture-protocol

Central server for hosting Suture repositories.

Transport layers:

LayerTechnologyDescription HTTPAxumREST API, middleware, auth, web UI gRPCTonic + ProstBidirectional streaming (14 RPCs) StorageSQLiteRepository metadata and blob storage

HTTP Routes (key endpoints):

MethodPathAuthDescription GET/healthzNoHealth check GET/POST/handshakeNoV1 handshake GET/POST/v2/handshakeNoV2 with capability negotiation POST/v2/pushNoPush patches + blobs POST/v2/pullNoPull patches + blobs GET/reposNoList repositories POST/reposAuthCreate repository GET/DELETE/repo/{repo_id}AuthGet/delete repo POST/auth/registerNoRegister user POST/auth/loginNoLogin, get Ed25519 token POST/auth/tokenAuthCreate auth token POST/auth/verifyNoVerify auth token GET/searchNoCross-repo search POST/lfs/batchAuthLFS batch upload/download POST/webhooksAuthCreate webhook POST/GET`/mirror/setupsyncstatus`AuthMirror management POST/GET/replication/peersAuthRaft peer management

gRPC Service (SutureHub):

Defined in crates/suture-hub/proto/suture.proto. 14 RPCs:

Handshake, ListRepos, GetRepoInfo, CreateRepo, DeleteRepo, ListBranches, CreateBranch, DeleteBranch, ListPatches, GetBlob, Push, Pull, GetTree, Search

Features:

  • Auth: Ed25519 key-based authentication
  • Webhooks: Event-driven notifications (push/branch events) with HMAC-SHA256 signing
  • S3 Backend (feature s3-backend): Blob storage via suture-s3 (AWS SigV4, MinIO compatible)
  • Raft Clustering (feature raft-cluster): Consensus via suture-raft for HA deployments
  • Mirrors: Repository mirroring support
  • Pagination: Cursor-based pagination for large result sets
  • LFS: Large file storage via batch API

suture-platform

Path: crates/suture-platform/ Depends on: suture-driver (all 17), suture-wasm-plugin

SaaS platform with web UI, authentication, billing, organizations, and merge API.

Architecture:

  • Axum web server with tower-http tracing
  • SQLite (WAL mode) via PlatformDb with Mutex<Connection>
  • JWT authentication (HS256, 7-day expiry, revocation support)
  • Rate limiting: In-memory sliding window per user/IP, tier-based limits
  • CORS: Permissive (configurable for production)
  • Stripe: Checkout sessions, portal, webhook handling with HMAC-SHA256 verification
  • OAuth: Google and GitHub (CSRF state tokens, one-time use)
  • WASM plugins: Runtime plugin loading and merge execution

See docs/api-reference.md for full endpoint documentation.


suture-raft

Path: crates/suture-raft/ Tests: 30

Raft consensus protocol implementation for hub clustering.

Key components:

ComponentDescription RaftNodeRaft node state machine (leader, follower, candidate) RaftTcpTransportTCP transport with 4-byte BE length + JSON wire format RaftRuntimeBackground tick loop, propose/apply channels, leader tracking SqliteRaftLogPersisted Raft log (gated on persist feature) HubCommandCommand enum for state machine replication

Protocol details:

  • Randomized election timeouts (Raft paper section 5.2) to prevent split-vote livelock
  • Leader election, log replication, commit
  • Multi-node 3-cluster integration test over real TCP
  • 3 Raft integration tests + 12 hub-Raft tests

suture-vfs

Path: crates/suture-vfs/ Tests: 28 (2 ignored — require root)

Exposes a Suture repository as a filesystem.

FeatureTechnologyDescription FUSE3 mountfuse3 + TokioRead/write access to repo as filesystem WebDAV serverAxumHTTP-based file access (macOS Finder, Windows Explorer) Path translationCustomMaps between filesystem paths and repository paths Inode allocationCustomStable inode assignment for FUSE operations

Integration tests (require root, #[ignore]d): mount read/write/modify/delete/stat, WebDAV serve.


suture-wasm-plugin

Path: crates/suture-wasm-plugin/

WASM plugin runtime for loading custom merge drivers at runtime.

ABI:

  • Version 1 ABI with version checking
  • PluginManager: Load, validate, list, and execute WASM plugins
  • validate_plugin(): Pre-load validation of Wasm modules
  • Plugin descriptor files (.suture-plugin) for discovery
  • discover_plugins(dir): Scan a directory for plugin descriptors

Integration with platform:

  • Plugins loaded at startup from plugins/ directory
  • Enterprise-tier users can upload plugins via REST API
  • merge_with_plugin() endpoint dispatches to loaded WASM drivers

suture-cli

Path: crates/suture-cli/ Tests: 32

Command-line interface using clap with derive macros.

64 subcommands organized in src/cmd/ (one file per command).

Key commands:

CommandDescription initInitialize repository (with --type and --template support) addStage files (recursive directory expansion) commitCreate patch from staged changes mergeMerge branches with semantic drivers (`-s ourstheirsmanualsemantic, --dry-run`) diffShow semantic or line diffs (--integrity, --classification, --summary, --name-only) logView patch history (--stat, --diff, --audit, --graph) push / pullRemote sync via HTTP protocol stashStash and restore changes rebaseRebase patches onto new base bisectBinary search for bug-introducing commit tuiLaunch terminal UI syncAuto-commit, pull, push (Google Drive replacement) doctorHealth checks (--fix auto-remediation) exportExport clean snapshot undoReflog-aware undo verifyEd25519 signature verification blamePer-line blame with range filtering (-L) grepSearch tracked content with regex switch / restoreModern alternatives to checkout archiveExport as tar.gz/tar/zip ls-remoteList remote branches without cloning timelineOTIO import/export/summary/diff reportBatch operations, export templates git importRead-only Git history import key generateEd25519 key generation hook list/run/editHook management

Supporting modules:

ModuleDescription driver_registry.rsBuilds DriverRegistry with all 17 builtin drivers display.rsTerminal output formatting and colors fuzzy.rsFuzzy matching for branch/tag/patch selection remote_proto.rsHTTP-based remote protocol implementation ref_utils.rsReference resolution utilities style.rsCLI styling helpers

suture-tui

Path: crates/suture-tui/ Tests: 31

Terminal UI built with ratatui.

7 tabs:

TabDescription StatusRepository status, staged/untracked files LogCommit history with graph BranchBranch management RemoteRemote operations ConflictMerge conflict resolution DiffFile diffs HelpKey bindings and documentation

Conflict resolver:

  • Line-by-line hunk resolution (replaces binary ours/theirs-only choice)
  • 1/2/3 keys: take ours, theirs, or both per hunk
  • j/k keys: navigate between conflict hunks
  • n/p keys: next/previous conflict file
  • a key: accept all remaining with last used resolution
  • Three-panel layout: file list, hunk detail, key bindings footer

suture-lsp

Path: crates/suture-lsp/ Tests: 11

Language Server Protocol implementation via tower-lsp.

Capabilities:

  • Hover information for patches
  • Diagnostics for merge conflicts
  • Workspace-aware repository operations
  • Activates for .suture directories

suture-daemon

Path: crates/suture-daemon/ Tests: 33

Background daemon for continuous operations.

FeatureImplementation File watchernotify crate for working tree change detection Shared memorymemmap2-based SHM for inter-process state Mount managerFUSE/WebDAV lifecycle management Auto-syncAutomatic push/pull to configured remotes PID managementPID file management, signal handling (SIGTERM, SIGHUP) Log rotationhumantime-based timestamps

Other Crates

CrateDescription suture-protocolBinary wire protocol with V2 handshake, Zstd compression, delta encoding suture-mergeStandalone merge library (published to crates.io as suture-merge v0.2) suture-s3S3-compatible blob storage (AWS SigV4, path/virtual-hosted, MinIO) suture-ooxmlShared OOXML infrastructure for DOCX/XLSX/PPTX drivers suture-nodeNode.js native addon via napi-rs suture-e2eEnd-to-end workflow tests (226 tests) suture-fuzzFuzz testing (6 targets: CAS hash, patch serialization, merge, touch-set) suture-benchCriterion benchmarks (44 functions) suture-pyPython bindings via PyO3

Data Model

Repository

The Repository is the top-level object (suture-core/src/repository/). It coordinates:


Repository
├── BlobStore (CAS)
│   └── .suture/objects/{2-char-prefix}/{62-char-hash}
├── PatchDag (in-memory)
│   └── Nodes: patch_id → [parent_ids], branches: name → tip_patch_id
├── MetadataStore (SQLite)
│   └── .suture/metadata.db
│       ├── patches table (serialized JSON)
│       ├── branches table (name → tip)
│       └── config key-value pairs
├── Working Set
│   └── Currently checked-out files, staged changes
└── Audit Log
    └── .suture/audit.jsonl (BLAKE3 hash chain)

Patch

The fundamental unit of change (suture-core/src/patch/types.rs):

FieldTypeDescription idHash (BLAKE3)Content-addressed identifier parent_idsVec<Hash>Parent patches (1 for linear, 2 for merge) operation_typeOperationTypeCreate, Delete, Modify, Move, Merge, Batch, Identity touch_setTouchSetSet of file paths this patch modifies target_pathOption<String>Target file path payloadVec<u8>Serialized operation data timestampi64Unix epoch seconds authorStringAuthor identifier messageStringHuman-readable description

The Batch operation type groups multiple FileChange entries into a single commit (standard CLI commit path).

FileChange

Within a Batch patch:

FieldTypeDescription pathStringRepository-relative file path content_hashHashBLAKE3 hash of file content (stored in CAS) operationFileOpAdd, Modify, Delete

Touch Set and Commutativity

Touch sets are the basis for commutativity detection. Two patches commute (can be applied in either order) if and only if their touch sets are disjoint. This enables conflict detection without full content comparison.

Branch

A branch maps a BranchName to a tip PatchId in the DAG.

Storage Layout


.suture/
├── objects/        # CAS blob storage (BLAKE3-indexed)
│   └── ab/         # 2-char hex prefix (256 buckets)
│       └── cdef... # Remaining 62 hex chars = blob filename
├── metadata.db     # SQLite: patches, branches, config, refs
├── HEAD            # Current branch reference
├── hooks/          # Executable hook scripts
├── keys/           # Ed25519 signing keys
├── config          # Per-repo TOML configuration
├── audit.jsonl     # Tamper-evident audit log
└── worktree        # Marker file for worktree checkouts

Merge Algorithm

Suture implements three-way merge with format-aware conflict detection:

Step-by-Step

  1. Compute merge base: PatchDag::lca() finds the Lowest Common Ancestor of the two branch tips
  2. Reconstruct file trees: Apply patches from merge base to each branch tip, obtaining three versions per file: base, ours, theirs
  3. Per-file driver lookup: Check if a semantic driver exists for the file extension via DriverRegistry
  4. Driver present: Call driver.merge(base, ours, theirs) (or merge_raw() for binary formats)
  5. No driver: Fall back to line-based text merge with conflict markers
  6. Conflict handling for binary formats (DOCX/XLSX/PPTX): Preserve "ours" version, generate .suture/conflicts/report.md

Semantic Merge (Format-Aware)

When a driver is available:

  1. Parse all three versions (base, ours, theirs) using the format-specific driver
  2. Compute structural diff using key-path based changes (not line-based)
  3. Classify changes:
  • Same: No change between base and either branch
  • Ours-only: Changed in ours only → take ours
  • Theirs-only: Changed in theirs only → take theirs
  • Both-changed-same: Both changed identically → take either (no conflict)
  • Both-changed-different: Both changed differently → conflict
  1. Auto-resolve: Take changed version for ours-only and theirs-only
  2. Detect conflicts: Both-changed-different entries produce conflicts
  3. Return: Some(merged_content) for clean merge, None for conflicts

Merge Strategies

StrategyFlagBehavior Semantic-s semantic (default)Try semantic drivers first, fall back to text merge Ours-s oursKeep our version for all conflicts Theirs-s theirsTake their version for all conflicts Manual-s manualLeave all conflicts for manual resolution

Dry Run

--dry-run previews the merge result without modifying the working tree. OOXML conflict handling is noted in the output.

API Reference

Platform REST API

MethodPathAuthDescription GET/healthzNoHealth check GET/NoWeb UI index GET/static/{*path}NoStatic assets POST/auth/registerNoCreate account POST/auth/loginNoLogin, get JWT GET/auth/meOptionalCurrent user info POST/auth/logoutOptionalRevoke token GET/auth/oauth/startNoStart OAuth flow GET/auth/google/callbackNoGoogle OAuth callback GET/auth/github/callbackNoGitHub OAuth callback POST/api/mergeOptionalThree-way semantic merge GET/api/driversNoList supported drivers GET/api/usageOptionalCurrent usage/limits GET/api/analyticsOptionalUsage analytics (Pro+) POST/api/orgsOptionalCreate org GET/api/orgsOptionalList user's orgs POST/api/orgs/{org_id}/inviteOptionalInvite member GET/api/orgs/{org_id}/membersOptionalList members PUT/api/orgs/{org_id}/members/{user_id}/roleOptionalUpdate role DELETE/api/orgs/{org_id}/members/{user_id}OptionalRemove member GET/api/invitationsOptionalList invitations POST/api/invitations/{invite_id}/acceptOptionalAccept invitation GET/api/pluginsNoList loaded plugins POST/api/plugins/uploadEnterpriseUpload WASM plugin POST/api/plugins/mergeOptionalMerge with plugin POST/billing/checkoutOptionalCreate checkout session POST/billing/portalOptionalCustomer portal GET/billing/subscriptionOptionalGet subscription info POST/billing/webhookNoStripe webhook GET/admin/usersAdminList all users

Hub REST API

MethodPathAuthDescription GET/healthzNoHealth check GET/POST/handshakeNoV1 version/capability negotiation GET/POST/v2/handshakeNoV2 with extended capabilities POST/v2/pushNoPush patches and blobs POST/v2/pullNoPull patches and blobs GET/reposNoList repositories POST/reposAuthCreate repository GET/repo/{repo_id}AuthGet repo info DELETE/repo/{repo_id}AuthDelete repository POST/auth/registerNoRegister user POST/auth/loginNoLogin (Ed25519) POST/auth/tokenAuthCreate auth token POST/auth/verifyNoVerify auth token GET/searchNoCross-repo search GET/activityNoActivity feed POST/lfs/batchAuthLFS batch operations POST/webhooksAuthCreate webhook POST/GET`/mirror/setupsyncstatus`AuthMirror management POST/GET/DELETE/replication/peersAuthRaft peer management

gRPC Service (Hub)

SutureHub service defined in crates/suture-hub/proto/suture.proto:

Handshake, ListRepos, GetRepoInfo, CreateRepo, DeleteRepo, ListBranches, CreateBranch, DeleteBranch, ListPatches, GetBlob, Push, Pull, GetTree, Search

Wire Protocol (suture-protocol)

Binary protocol with Zstd compression for CLI-to-Hub communication:

  • V2 handshake with capability negotiation
  • Delta encoding for efficient transfer
  • Batch operations for push/pull

Security Model

Authentication

Platform (JWT):

  • HS256 JWT with configurable secret (SUTURE_JWT_SECRET)
  • 7-day session duration
  • Token revocation via revoked_tokens table (checked on every authenticated request)
  • Revoked tokens auto-cleaned on verification

Hub (Ed25519):

  • Ed25519 key-based authentication
  • Token creation and verification endpoints
  • Key generation via suture key generate

OAuth (Google, GitHub):

  • Authorization code flow with PKCE-style state tokens
  • CSRF protection: UUID v4 state stored in oauth_states table with 10-minute expiry
  • State is one-time use (deleted after validation)
  • Provider identity stored as oauth:<provider_id> marker in password_hash field

Authorization

Tier-based rate limiting (per-minute sliding window):

TierRate LimitMerge Limit/moStorageReposPrice Free30 req/min100100 MB5$0 Pro300 req/min10,00010 GBUnlimited$9/seat Enterprise3,000 req/minUnlimited100 GBUnlimited$29/seat

Rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After

Anonymous requests: 10 req/min per IP (uses X-Forwarded-For header)

Stripe Integration

  • Webhook HMAC verification: Stripe-Signature header parsed for t=<timestamp>,v1=<signature>. HMAC-SHA256 computed over timestamp.payload. Timestamp must be within 300 seconds to prevent replay attacks.
  • Customer management: Auto-create Stripe customer on first checkout. Customer ID stored in accounts table.
  • Subscription lifecycle: Handles checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed
  • Grace period: 7-day grace period on payment failure before downgrade
  • Price IDs: Configured via STRIPE_PRICE_PRO and STRIPE_PRICE_ENTERPRISE env vars

Self-Hosted (Hub)

  • Ed25519 token-based auth
  • Per-IP rate limiting
  • Repository-level access control
  • Webhook delivery with HMAC-SHA256 signing
  • Branch protection rules

Input Validation

  • RepoPath::new() rejects .., absolute paths, null bytes (path traversal protection)
  • BranchName::new() validates non-empty, no null bytes
  • Email validation: must contain @, max 254 characters
  • Password: minimum 8 characters
  • Org names: 2-39 alphanumeric characters (hyphens and underscores allowed)
  • Blob size limits: 50MB max (max_blob_size)
  • Page size limits: 10K max (max_page_size)

Audit Trail

  • Append-only JSONL with BLAKE3 hash chaining
  • Optional Ed25519 signatures for non-repudiation
  • suture log --audit for compliance reporting
  • Export formats: JSON, CSV, text

Error Handling

All crates use thiserror for error types:

Error TypeSourceDescription RepoErrorsuture-coreRepository operations (init, commit, merge) CasErrorsuture-coreContent-addressable storage DagErrorsuture-coreDAG operations (cycle detection, missing patches) DriverErrorsuture-driverDriver parsing and merge errors MetaErrorsuture-coreSQLite metadata operations MergeErrorsuture-coreMerge results and failures OrgErrorsuture-platformOrganization management errors

Dependency Graph


suture-common (no deps)
    ↑
suture-core → suture-common
    ↑
suture-driver → suture-core, suture-common
    ↑
suture-merge → suture-driver
suture-ooxml → suture-common
suture-driver-{docx,xlsx,pptx} → suture-driver, suture-ooxml
suture-driver-{json,yaml,toml,csv,xml,...} → suture-driver
suture-protocol → suture-common
suture-cli → suture-core, suture-common, suture-driver, suture-merge, all drivers
suture-hub → suture-common, suture-core, suture-protocol
suture-raft (standalone)
suture-s3 (standalone)
suture-platform → suture-driver (all 17), suture-wasm-plugin
suture-vfs → suture-core
suture-tui → suture-core
suture-lsp → suture-core
suture-daemon → suture-core
suture-wasm-plugin (standalone)

Total: 37 crates in workspace (2 excluded: suture-py, desktop-app).