| Crates.io | invar-cli |
| lib.rs | invar-cli |
| version | 1.0.0 |
| created_at | 2025-11-25 16:35:41.953613+00 |
| updated_at | 2025-11-25 16:35:41.953613+00 |
| description | The Unchanging Key for Changing Data - Generate immutable structural state roots for cryptographic cache keys |
| homepage | https://github.com/swyrknt/invar-cli |
| repository | https://github.com/swyrknt/invar-cli |
| max_upload_size | |
| id | 1950052 |
| size | 209,290 |
The Unchanging Key for Changing Data
A high-precision CLI tool for generating deterministic, content-addressable identifiers from any data source. Built for CI/CD pipelines, build systems, and content-addressed storage.
Invar generates immutable structural state roots (Invar Keys) from arbitrary input data. Unlike traditional hashing, Invar processes data byte-by-byte through a mathematical synthesis engine, producing keys that represent the exact structural identity of your data.
Download from GitHub Releases:
# Linux (x86_64)
curl -LO https://github.com/swyrknt/invar-cli/releases/latest/download/invar-linux-x86_64.tar.gz
tar -xzf invar-linux-x86_64.tar.gz
sudo mv invar /usr/local/bin/
# macOS (Apple Silicon)
curl -LO https://github.com/swyrknt/invar-cli/releases/latest/download/invar-darwin-aarch64.tar.gz
tar -xzf invar-darwin-aarch64.tar.gz
sudo mv invar /usr/local/bin/
cargo install invar
git clone https://github.com/swyrknt/invar-cli.git
cd invar-cli
cargo install --path .
docker pull ghcr.io/swyrknt/invar-cli:latest
# Usage
echo "test" | docker run --rm -i ghcr.io/swyrknt/invar-cli gen
docker run --rm -v $(pwd):/data ghcr.io/swyrknt/invar-cli gen --directory /data/src
# Generate key from a file
invar gen --file package-lock.json
# Generate key from stdin
echo "v1.0.1" | invar gen
# Generate key from inline data
invar gen --data "Hello, World!"
# Generate key from a directory
invar gen --directory ./src
# Verify data matches an expected key
invar check --file package-lock.json --expected <key>
# Watch for changes
invar watch ./src --recursive
# From file
invar gen --file config.json
# From stdin
cat data.bin | invar gen
# From inline string
invar gen --data "my-data-v1.0"
# JSON output with metadata
invar gen --file data.txt --output json
Hash entire directories with deterministic, order-independent results:
# Hash a directory recursively
invar gen --directory ./src
# Include hidden files
invar gen --directory ./src --include-hidden
# JSON output with file count and size
invar gen --directory ./src --output json
# Output: {"key": "abc123...", "file_count": 42, "total_bytes": 123456}
Invar respects .gitignore and .invarignore files by default:
# Default behavior (respects .gitignore and .invarignore)
invar gen --directory ./src
# Disable .gitignore
invar gen --directory ./src --no-gitignore
# Disable .invarignore
invar gen --directory ./src --no-invarignore
Create a .invarignore file for invar-specific exclusions:
# .invarignore - patterns specific to invar
*.log
build/
dist/
*.mp4
Process large files with constant memory usage:
# Stream large files
invar gen --file large-video.mp4 --stream
# With progress reporting (every N MB)
invar gen --file large-video.mp4 --stream --progress 100
Monitor files or directories for changes:
# Watch a single file
invar watch config.yaml
# Watch a directory recursively
invar watch ./src --recursive
# Custom debounce interval (milliseconds)
invar watch ./src --recursive --debounce 1000
# JSON output for scripting
invar watch ./src --recursive --output json
# Generate a key
KEY=$(invar gen --file package-lock.json)
# Later, verify the file hasn't changed
invar check --file package-lock.json --expected "$KEY"
# Verify a directory
invar check --directory ./src --expected "$KEY"
# GitHub Actions
- name: Generate cache key
run: echo "CACHE_KEY=$(invar gen --directory src)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: build-${{ env.CACHE_KEY }}
# Skip rebuild if source unchanged
CURRENT=$(invar gen --directory src)
CACHED=$(cat .build-cache 2>/dev/null || echo "")
if [ "$CURRENT" = "$CACHED" ]; then
echo "Source unchanged, skipping build"
else
make build
echo "$CURRENT" > .build-cache
fi
# Store files by content hash
KEY=$(invar gen --file document.pdf)
cp document.pdf "storage/$KEY.pdf"
# Detect configuration changes
if ! invar check --file config.yaml --expected "$STORED_KEY"; then
echo "Configuration changed, reloading..."
reload_configuration
fi
$ invar gen --data "test"
a94a8fe5ccb19ba61c4c0873d391e987982fbbd3a1e3...
$ invar gen --data "test" --output json
{
"key": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3...",
"length_bytes": 32
}
$ invar gen --directory ./src --output json
{
"key": "abc123...",
"file_count": 42,
"total_bytes": 123456,
"skipped": []
}
invar gen (alias: g)Generate an Invar key from input data.
| Option | Short | Description |
|---|---|---|
--file <PATH> |
-f |
Read from file |
--data <STRING> |
-d |
Read from string |
--directory <PATH> |
Hash directory recursively | |
--stream |
Use streaming mode (low memory) | |
--progress <MB> |
Report progress every N MB | |
--output <FORMAT> |
-o |
Output format: text or json |
--include-hidden |
Include hidden files (directories) | |
--follow-links |
Follow symbolic links | |
--no-gitignore |
Ignore .gitignore patterns | |
--no-invarignore |
Ignore .invarignore patterns |
invar check (alias: c)Verify data produces an expected key.
| Option | Short | Description |
|---|---|---|
--expected <KEY> |
-e |
Expected 64-character hex key |
| (plus all gen options) |
Exit codes: 0 = match, 1 = mismatch or error
invar watch (alias: w)Watch for file changes and report new keys.
| Option | Short | Description |
|---|---|---|
<PATH> |
File or directory to watch | |
--recursive |
-r |
Watch subdirectories |
--debounce <MS> |
Debounce interval (default: 500) | |
--output <FORMAT> |
-o |
Output format: text or json |
Invar uses the Distinction Calculus to generate structural identifiers:
D_root = synthesize(D_root, D_byte)This ensures:
See the examples directory for:
# Build
cargo build --release
# Test (87 tests)
cargo test
# Lint
cargo clippy -- -D warnings
# Format
cargo fmt
Dual-licensed under MIT or Apache 2.0 at your option.