This project has been generated by claude code
A lightweight Linux daemon that manages counter pools and UUID-v4 pools over a Unix socket. Create named pools, read auto-incrementing counters or generate unique UUIDs, and let the daemon handle persistence across restarts.
envcounter is composed of two binaries:
envcounterd— the background daemon that holds pool state in memory, listens on a Unix socket, and persists state to disk on shutdown.envcounter-cli— the command-line client that talks to the daemon.
- Counter pools — auto-incrementing integer counters with configurable step and initial value.
- UUID-v4 pools — generate cryptographically random UUIDs on demand.
- Persistent state — on SIGTERM/SIGINT the daemon saves all pool state to disk and restores it on next startup. No data loss across service restarts or system reboots.
- Unix socket IPC — fast, local-only communication via
$XDG_RUNTIME_DIR/envcounter.sock. No network exposure. - Async and concurrent — built on Tokio; handles multiple simultaneous clients.
- Systemd user service — runs unprivileged under your user session. No root required.
- Multiple output formats — list pools as an aligned table or as JSON for scripting.
Requires Rust 1.85+ (edition 2024).
git clone https://github.com/youruser/envcounter.git
cd envcounter
cargo build --releaseThe binaries will be at target/release/envcounterd and target/release/envcounter-cli.
To install them into ~/.cargo/bin:
cargo install --path .mkdir -p ~/.config/systemd/user
cp contrib/envcounterd.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now envcounterdCheck status:
systemctl --user status envcounterdIf you prefer running manually:
envcounterdCounters hold an integer value that increments by a configurable step on every read.
envcounter-cli counter new <name> [--step <n>] [--initial <n>]--step(default:1) — how much the counter increments on each read.--initial(default:0) — the starting value.
# Simple counter starting at 0, incrementing by 1
envcounter-cli counter new request_count
# Counter starting at 1000, incrementing by 100
envcounter-cli counter new batch_id --step 100 --initial 1000Returns the current value, then increments the counter by its step.
envcounter-cli counter read batch_id
# 1000
envcounter-cli counter read batch_id
# 1100
envcounter-cli counter read batch_id
# 1200Returns the current value without changing it. Useful for inspecting state.
envcounter-cli counter seek batch_id
# 1300
envcounter-cli counter seek batch_id
# 1300 (unchanged)Resets the counter back to its initial value.
envcounter-cli counter reset batch_id
envcounter-cli counter seek batch_id
# 1000envcounter-cli counter rename batch_id job_idenvcounter-cli counter rm job_idUUID pools generate a new random UUID-v4 on every read. They have no mutable state — they exist as named entry points for UUID generation.
envcounter-cli uuid new session_idsenvcounter-cli uuid read session_ids
# 3f8a92c1-7b4d-4e2f-a891-5c3d7e8f1b2a
envcounter-cli uuid read session_ids
# a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5dEvery call returns a unique UUID.
envcounter-cli uuid rm session_idsenvcounter-cli listNAME TYPE DETAILS
batch_id counter value=1200 step=100 initial=1000
request_count counter value=5 step=1 initial=0
session_ids uuid -
envcounter-cli list --type counterNAME TYPE DETAILS
batch_id counter value=1200 step=100 initial=1000
request_count counter value=5 step=1 initial=0
envcounter-cli list --format json[
{
"name": "batch_id",
"type": "counter",
"value": 1200,
"step": 100,
"initial": 1000
},
{
"name": "session_ids",
"type": "uuid"
}
]Combine both flags:
envcounter-cli list --format json --type uuidGenerate unique, sequential identifiers without relying on external services or file-based locks.
#!/bin/bash
envcounter-cli counter new deploy_id --initial 1 2>/dev/null
ID=$(envcounter-cli counter read deploy_id)
echo "Starting deployment #${ID}..."Use a counter with a large step to partition work across ranges.
envcounter-cli counter new chunk_offset --step 10000 --initial 0
# Worker 1 gets offset 0
OFFSET=$(envcounter-cli counter read chunk_offset)
process_records --offset "$OFFSET" --limit 10000
# Worker 2 gets offset 10000
OFFSET=$(envcounter-cli counter read chunk_offset)
process_records --offset "$OFFSET" --limit 10000Embed a UUID in every outgoing request for distributed tracing.
envcounter-cli uuid new trace_ids
curl -H "X-Request-ID: $(envcounter-cli uuid read trace_ids)" https://api.example.com/dataA persistent, monotonically increasing build counter that survives reboots.
envcounter-cli counter new build_number --initial 1
BUILD=$(envcounter-cli counter read build_number)
docker build -t myapp:build-${BUILD} .Use envcounter-cli in subshells to inject dynamic values:
export REQUEST_ID=$(envcounter-cli uuid read req_pool)
export SEQ_NUM=$(envcounter-cli counter read seq)
envsubst < config.template > config.yamlenvcounter-cli ──Unix socket──▶ envcounterd
│
┌──────┴──────┐
│ AppState │
│ (RwLock) │
├─────────────┤
│ pool_a: Ctr │
│ pool_b: Uuid│
│ pool_c: Ctr │
└──────┬──────┘
│
on shutdown
│
▼
~/.local/state/envcounter/
state.json
- Protocol: newline-delimited JSON over a Unix socket. Each request is a single JSON line; each response is a single JSON line.
- Concurrency:
Arc<RwLock<HashMap<String, Pool>>>— the critical section is minimal (integer arithmetic), so a single lock provides excellent performance. - Socket path:
$XDG_RUNTIME_DIR/envcounter.sock(typically/run/user/<uid>/envcounter.sock). - State path:
$XDG_STATE_HOME/envcounter/state.json(typically~/.local/state/envcounter/state.json). Written atomically via temp file + rename.
| Command | Description |
|---|---|
counter new <name> [-s step] [-i initial] |
Create a counter pool |
counter read <name> |
Get current value and increment |
counter seek <name> |
Get current value (no increment) |
counter rm <name> |
Remove a counter |
counter rename <name> <new_name> |
Rename a counter |
counter reset <name> |
Reset counter to initial value |
uuid new <name> |
Create a UUID pool |
uuid read <name> |
Generate a new UUID-v4 |
uuid rm <name> |
Remove a UUID pool |
list [-f table|json] [-t counter|uuid] |
List pools |
MIT