synwire-storage
Product-scoped storage path management for the Synwire workspace. Provides StorageLayout for computing stable, platform-correct paths for all Synwire subsystems, and RepoId/WorktreeId for two-level project identity.
Quick start
use ;
use Path;
let layout = new?;
let worktree = for_path?;
// Durable data
println!;
println!;
println!;
// Cache (may be deleted and regenerated)
println!;
println!;
StorageLayout
StorageLayout computes all Synwire storage paths for a given product name using a consistent hierarchy rooted at the platform data and cache directories.
Path layout
$XDG_DATA_HOME/<product>/ (Linux)
~/Library/Application Support/<product>/ (macOS)
%APPDATA%/<product>/ (Windows)
├── sessions/<session_id>.db — checkpoint databases
├── experience/<worktree_key>.db — per-worktree experience pool
├── skills/ — global agent skills
├── logs/ — rotating log files
├── daemon.pid — daemon PID file
├── daemon.sock — daemon UDS socket
└── global/
├── registry.json — project registry
├── experience.db — cross-project experience
├── dependencies.db — cross-project dependency index
└── config.json — global product config
$XDG_CACHE_HOME/<product>/
├── indices/<worktree_key>/ — vector + BM25 indices
├── graphs/<worktree_key>/ — code dependency graphs
├── communities/<worktree_key>/ — community detection state
├── lsp/<worktree_key>/ — LSP server caches
├── models/ — embedding model download cache
└── repos/<owner>/<repo>/ — cloned repositories
Durable vs cache
| Location | Durability | Examples |
|---|---|---|
$DATA/<product>/ |
Durable — never delete | Sessions, experience, skills, logs |
$CACHE/<product>/ |
Regenerable — safe to delete | Indices, graphs, communities, cloned repos |
Path methods
| Method | Returns | Purpose |
|---|---|---|
session_db(id) |
PathBuf |
SQLite checkpoint DB for a session |
experience_db(worktree) |
PathBuf |
Per-worktree experience pool |
skills_dir() |
PathBuf |
Global agent skills directory |
logs_dir() |
PathBuf |
Rotating log files |
daemon_pid_file() |
PathBuf |
Daemon PID file |
daemon_socket() |
PathBuf |
Daemon Unix domain socket |
global_experience_db() |
PathBuf |
Cross-project experience |
global_dependency_db() |
PathBuf |
Cross-project dependency index |
index_cache(worktree) |
PathBuf |
Vector + BM25 index cache |
graph_dir(worktree) |
PathBuf |
Code dependency graph |
communities_dir(worktree) |
PathBuf |
Community detection state |
repos_cache() |
PathBuf |
Root of cloned repos |
repo_cache(owner, repo) |
PathBuf |
A specific cloned repo |
Construction
use ;
// Platform-default paths
let layout = new?;
// Override root (useful in tests)
let layout = with_root;
// Apply programmatic config on top
let config = StorageConfig ;
let layout = new?.with_config;
Project-local config
Each project can supply .<product>/config.json to override paths for that project:
Load it:
let cfg = layout.load_project_config?;
if let Some = cfg
Two-level identity
Synwire identifies projects at two levels to support multi-worktree repositories cleanly.
RepoId
RepoId is stable across all clones and worktrees of the same repository. It is derived from:
- Git available: SHA-1 of the first (root) commit (
git rev-list --max-parents=0 HEAD) - Git unavailable: SHA-256 of the canonical directory path
use RepoId;
use Path;
let id = for_path?;
println!; // e.g. "a3f2c1..."
WorktreeId
WorktreeId identifies a specific working copy within a repository family. It combines RepoId with a SHA-256 of the canonicalised worktree root path.
use WorktreeId;
use Path;
let wid = for_path?;
println!; // "a3f2c1...-def456789012"
println!; // "myrepo@main"
The key() method produces a compact string safe for use in directory names: <repo_id>-<worktree_hash[:12]>.
Why two levels?
| Scenario | RepoId | WorktreeId |
|---|---|---|
| Two clones of same repo | Same | Different |
| Same repo, two branches (worktrees) | Same | Different |
| Two unrelated repos | Different | Different |
This lets the experience pool and dependency index be shared across branches of the same repo (via RepoId), while vector indices are per-worktree (via WorktreeId).
Configuration
| Source | Priority | Applies to |
|---|---|---|
SYNWIRE_DATA_DIR env var |
Highest | Data home |
SYNWIRE_CACHE_DIR env var |
Highest | Cache home |
StorageLayout::with_root(root, name) |
Explicit | Both |
.<product>/config.json |
Per-project | Either |
Platform default (directories::BaseDirs) |
Lowest | Both |
CLI override example:
SYNWIRE_DATA_DIR=/mnt/data/synwire
Migration
Future versions will provide StorageLayout::migrate(from_version) to move or rewrite paths between schema versions. In v0.1, no migration is needed — all paths are new.
Path mapping from pre-StorageLayout layouts:
| Old path | New path |
|---|---|
$CACHE/synwire/indices/ |
StorageLayout::index_cache(worktree) |
$CACHE/synwire/graphs/ |
StorageLayout::graph_dir(worktree) |
$DATA/synwire/skills/ |
StorageLayout::skills_dir() |
See the migration guide for shell commands.
Feature flags
No optional features. Always depends on directories and sha2.