Skip to content

Commit 1daba17

Browse files
tcconnallyclaude
andcommitted
fix(#424): factor DB emptiness into default resolution; repair bootstrap.sh binary name
Follow-up to #421/#423. Purely path-based default-DB precedence let a stale, empty higher-precedence DB shadow a live lower-precedence one (the exact reported case: empty ~/.mimir/data/mimir.db chosen over a live ~/mimir.db). - resolve_default_db now takes a keyless entity-count probe. Only when the highest-precedence *existing* candidate is known-empty (Some(0)) does it prefer the highest-precedence known-non-empty candidate. Unknown candidates (locked/corrupt/not-yet-a-vault -> None) are never demoted-on nor promoted-to, so it degrades to the current path order + split-brain warning. - probe_entity_count opens candidates read-only (no schema init / WAL churn, unlike Database::open) and counts entities; a row COUNT needs no key since encryption is per-field. - Resolution + warnings centralized in normalize_default_db(), run once in main() before the command match, so serve and all maintenance subcommands open the same resolved DB (replaces the scattered check_legacy_db calls). default_db_path() (clap's eager default) stays path-only and side-effect-free. - 5 new unit tests cover the emptiness cases; the 5 existing #421 precedence tests updated to the new signature (unchanged assertions via an all-unknown probe). Full bin suite: 338 passed. - scripts/bootstrap.sh looked for target/release/mimir, which the perseus-vault crate no longer emits (build succeeded then failed to find the binary). Now builds/installs perseus-vault + mimir/mneme compat symlinks, defaults to perseus-vault.db, and uses the serve subcommand — matching install.sh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 52a9a6a commit 1daba17

3 files changed

Lines changed: 321 additions & 107 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ All notable changes to Perseus Vault (formerly Mimir/Mneme) are documented here.
55

66
## [Unreleased]
77

8+
### Fixed
9+
- Default DB resolution now factors in emptiness (#424, follow-up to #421):
10+
when the database path is the implicit default (no `--db`, no
11+
`$MIMIR_DB_PATH`) and the highest-precedence candidate DB is *known-empty*
12+
(`SELECT COUNT(*) FROM entities == 0` — a keyless read, works under
13+
encryption), a lower-precedence but *non-empty* candidate is preferred
14+
instead. This fixes the reported case where a stale-empty
15+
`~/.mimir/data/mimir.db` shadowed a live `~/mimir.db`. Candidates that can't
16+
be read (locked/corrupt/not-yet-a-vault) are treated as unknown — never
17+
demoted-on and never promoted-to — so behavior degrades gracefully to the
18+
path-based order plus the existing split-brain warning. Resolution + its
19+
warnings are now performed once in `main()` (`normalize_default_db`), so
20+
`serve` and every maintenance subcommand open the same resolved DB
21+
(previously only a handful of sites warned). `default_db_path()` (clap's
22+
eager default) stays path-only and side-effect-free.
23+
- `scripts/bootstrap.sh` looked for a `target/release/mimir` binary that the
24+
`perseus-vault`-named crate no longer produces (the build would report
25+
success then fail to find the binary). It now builds/installs `perseus-vault`
26+
with `mimir`/`mneme` compat symlinks, defaults to `perseus-vault.db`, and
27+
uses the `serve` subcommand — matching `scripts/install.sh` (#424).
28+
829
### Added
930
- History retention mechanism (#398): entity_history can now be bounded via
1031
env knobs — `MIMIR_HISTORY_MAX_AGE_DAYS`, `MIMIR_HISTORY_MAX_VERSIONS_PER_KEY`

scripts/bootstrap.sh

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
#!/usr/bin/env bash
22
# =============================================================================
3-
# Mimir One-Shot Bootstrap
3+
# Perseus Vault One-Shot Bootstrap (build from source)
44
# Persistent memory engine for AI agents — MCP JSON-RPC stdio server
55
#
66
# Usage:
7-
# curl -sSL https://raw.githubusercontent.com/Perseus-Computing-LLC/mimir/main/scripts/bootstrap.sh | bash
7+
# curl -sSL https://raw.githubusercontent.com/Perseus-Computing-LLC/perseus-vault/main/scripts/bootstrap.sh | bash
88
#
99
# What this does:
1010
# 1. Installs system dependencies (Rust toolchain via rustup, build tools)
11-
# 2. Clones and builds Mimir from source (release binary)
12-
# 3. Installs the binary to ~/.local/bin/mimir
11+
# 2. Clones and builds Perseus Vault from source (release binary)
12+
# 3. Installs the binary to ~/.local/bin/perseus-vault (+ mimir/mneme compat symlinks)
1313
# 4. Creates the data directory and generates .env defaults
1414
# 5. Verifies the installation and prints a success summary
1515
#
16-
# Idempotent — safe to re-run. Existing binary is only rebuilt if
17-
# FORCE=1 or the repo checkout is stale.
16+
# Prefer scripts/install.sh if you just want a prebuilt binary; this script is
17+
# for building from source. Idempotent — safe to re-run. Existing binary is
18+
# only rebuilt if FORCE=1 or the repo checkout is stale.
1819
# =============================================================================
1920
set -euo pipefail
2021

@@ -33,18 +34,23 @@ info() { printf "${CYAN}→${NC} %s\n" "$*"; }
3334
header() { printf "\n${BOLD}══ %s ══${NC}\n" "$*"; }
3435

3536
FORCE="${FORCE:-0}"
36-
MIMIR_REPO="https://github.com/Perseus-Computing-LLC/mimir.git"
37+
# Repo redirects from the historical mimir/mneme names, but use the canonical
38+
# one so the clone URL matches what users see everywhere else.
39+
VAULT_REPO="https://github.com/Perseus-Computing-LLC/perseus-vault.git"
40+
# Script-local dirs. NOTE: MIMIR_DB_PATH is the *real* env var the binary reads
41+
# (see default_db_path() in src/main.rs), so it keeps its name for compatibility;
42+
# the default filename is the canonical perseus-vault.db.
3743
MIMIR_DIR="${MIMIR_DIR:-$HOME/.mimir}"
3844
MIMIR_BIN_DIR="${MIMIR_BIN_DIR:-$HOME/.local/bin}"
3945
MIMIR_DATA_DIR="${MIMIR_DATA_DIR:-$HOME/.mimir/data}"
40-
MIMIR_DB_PATH="${MIMIR_DB_PATH:-$MIMIR_DATA_DIR/mimir.db}"
46+
MIMIR_DB_PATH="${MIMIR_DB_PATH:-$MIMIR_DATA_DIR/perseus-vault.db}"
4147
WORKSPACE="${WORKSPACE:-$(pwd)}"
4248

4349
echo ""
4450
echo "============================================"
45-
echo " Mimir One-Shot Bootstrap"
51+
echo " Perseus Vault One-Shot Bootstrap"
4652
echo " Persistent memory engine for AI agents"
47-
echo " github.com/Perseus-Computing-LLC/mimir"
53+
echo " github.com/Perseus-Computing-LLC/perseus-vault"
4854
echo "============================================"
4955

5056
# ── Step 1: System dependencies ─────────────────────────────────────────────
@@ -98,7 +104,7 @@ fi
98104
if command -v cc &>/dev/null; then
99105
ok "C compiler: $(cc --version 2>&1 | head -1)"
100106
else
101-
fail "C compiler is required to build Mimir (rusqlite with bundled SQLite). Install build-essential or equivalent."
107+
fail "C compiler is required to build Perseus Vault (rusqlite with bundled SQLite). Install build-essential or equivalent."
102108
fi
103109

104110
# Check/install Rust
@@ -127,8 +133,8 @@ else
127133
fi
128134
fi
129135

130-
# ── Step 2: Clone / update Mimir repo ───────────────────────────────────────
131-
header "Step 2: Clone & build Mimir"
136+
# ── Step 2: Clone / update repo ─────────────────────────────────────────────
137+
header "Step 2: Clone & build Perseus Vault"
132138

133139
if [ -d "$MIMIR_DIR/.git" ]; then
134140
info "Updating existing checkout at $MIMIR_DIR..."
@@ -143,40 +149,46 @@ if [ -d "$MIMIR_DIR/.git" ]; then
143149
ok "Repo is up to date"
144150
fi
145151
else
146-
info "Cloning Mimir from GitHub..."
152+
info "Cloning Perseus Vault from GitHub..."
147153
rm -rf "$MIMIR_DIR"
148-
git clone --depth 1 "$MIMIR_REPO" "$MIMIR_DIR"
154+
git clone --depth 1 "$VAULT_REPO" "$MIMIR_DIR"
149155
fi
150156

151-
# Build release binary
152-
info "Building Mimir (release)..."
157+
# Build release binary. The crate/bin is named perseus-vault, so cargo emits
158+
# target/release/perseus-vault (this path was stale — it used to look for a
159+
# `mimir` binary that no longer exists, #424).
160+
info "Building Perseus Vault (release)..."
153161
cd "$MIMIR_DIR"
154162
cargo build --release 2>&1 | tail -5
155-
BINARY="$MIMIR_DIR/target/release/mimir"
163+
BINARY="$MIMIR_DIR/target/release/perseus-vault"
156164

157165
if [ ! -f "$BINARY" ]; then
158-
fail "Build failed. Check the output above for errors."
166+
fail "Build failed (expected $BINARY). Check the output above for errors."
159167
fi
160168
ok "Binary built: $BINARY ($(du -h "$BINARY" | cut -f1))"
161169

162170
# ── Step 3: Install binary ──────────────────────────────────────────────────
163171
header "Step 3: Install binary"
164172

165173
mkdir -p "$MIMIR_BIN_DIR"
166-
cp "$BINARY" "$MIMIR_BIN_DIR/mimir"
167-
chmod +x "$MIMIR_BIN_DIR/mimir"
174+
cp "$BINARY" "$MIMIR_BIN_DIR/perseus-vault"
175+
chmod +x "$MIMIR_BIN_DIR/perseus-vault"
176+
# Backward-compatible names so existing configs referencing mimir/mneme keep
177+
# working (mirrors scripts/install.sh).
178+
ln -sf "$MIMIR_BIN_DIR/perseus-vault" "$MIMIR_BIN_DIR/mimir"
179+
ln -sf "$MIMIR_BIN_DIR/perseus-vault" "$MIMIR_BIN_DIR/mneme"
168180

169181
# macOS Apple silicon: a freshly built (unsigned) binary is SIGKILLed on first
170-
# run — `mimir --version` prints "Killed: 9" with no other output (#422). Apply
171-
# an ad-hoc code signature so it launches. Guarded by Darwin + arm64 so it is a
172-
# no-op on Intel macOS and other platforms.
182+
# run — `perseus-vault --version` prints "Killed: 9" with no other output
183+
# (#422). Apply an ad-hoc code signature so it launches. Guarded by Darwin +
184+
# arm64 so it is a no-op on Intel macOS and other platforms.
173185
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ] && command -v codesign >/dev/null 2>&1; then
174186
info "Ad-hoc code-signing binary (macOS Apple silicon, #422)..."
175-
if codesign --force --sign - "$MIMIR_BIN_DIR/mimir" 2>/dev/null; then
187+
if codesign --force --sign - "$MIMIR_BIN_DIR/perseus-vault" 2>/dev/null; then
176188
ok "Ad-hoc code-signed"
177189
else
178-
warn "Could not code-sign. If 'mimir' is Killed: 9, run:"
179-
warn " codesign --force --sign - $MIMIR_BIN_DIR/mimir"
190+
warn "Could not code-sign. If 'perseus-vault' is Killed: 9, run:"
191+
warn " codesign --force --sign - $MIMIR_BIN_DIR/perseus-vault"
180192
fi
181193
fi
182194

@@ -186,12 +198,12 @@ case ":$PATH:" in
186198
*) export PATH="$MIMIR_BIN_DIR:$PATH" ;;
187199
esac
188200

189-
if command -v mimir &>/dev/null; then
190-
MIMIR_VER=$(mimir --version 2>&1 || echo "unknown")
191-
ok "mimir installed to $MIMIR_BIN_DIR/mimir"
192-
ok "Version: $MIMIR_VER"
201+
if command -v perseus-vault &>/dev/null; then
202+
VAULT_VER=$(perseus-vault --version 2>&1 || echo "unknown")
203+
ok "perseus-vault installed to $MIMIR_BIN_DIR/perseus-vault"
204+
ok "Version: $VAULT_VER"
193205
else
194-
fail "mimir not found on PATH after install. Check $MIMIR_BIN_DIR"
206+
fail "perseus-vault not found on PATH after install. Check $MIMIR_BIN_DIR"
195207
fi
196208

197209
# ── Step 4: Create data directory ───────────────────────────────────────────
@@ -209,7 +221,7 @@ fi
209221
if [ ! -f "$MIMIR_DB_PATH" ]; then
210222
info "Warming up database at $MIMIR_DB_PATH..."
211223
# Brief serve+kill to trigger DB creation
212-
timeout 2 mimir --db "$MIMIR_DB_PATH" 2>/dev/null || true
224+
timeout 2 perseus-vault serve --db "$MIMIR_DB_PATH" 2>/dev/null || true
213225
if [ -f "$MIMIR_DB_PATH" ]; then
214226
ok "Database created: $MIMIR_DB_PATH"
215227
else
@@ -223,7 +235,7 @@ fi
223235
header "Step 5: Environment"
224236

225237
ENV_FILE="$WORKSPACE/.env"
226-
MIMIR_ENV_BLOCK="# ── Mimir ──────────────────────────────────────────────────────────────
238+
MIMIR_ENV_BLOCK="# ── Perseus Vault ──────────────────────────────────────────────────────
227239
# Database path (default shown)
228240
MIMIR_DB_PATH=$MIMIR_DB_PATH
229241
"
@@ -240,8 +252,8 @@ else
240252
BOOTSTRAP_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u)
241253
cat > "$ENV_FILE" << ENVEOF
242254
# =============================================================================
243-
# Mimir Environment
244-
# Generated by Mimir bootstrap — ${BOOTSTRAP_DATE}
255+
# Perseus Vault Environment
256+
# Generated by Perseus Vault bootstrap — ${BOOTSTRAP_DATE}
245257
# =============================================================================
246258
247259
# Database path
@@ -259,38 +271,35 @@ fi
259271
header "Step 6: Verify binary"
260272

261273
# Quick smoke test: start server directly, check it initializes
262-
SMOKE_OUT=$(timeout 2 mimir --db "$MIMIR_DB_PATH" 2>&1 </dev/null || true)
274+
SMOKE_OUT=$(timeout 2 perseus-vault serve --db "$MIMIR_DB_PATH" 2>&1 </dev/null || true)
263275
if echo "$SMOKE_OUT" | grep -q "MCP server ready"; then
264276
ok "MCP server initializes correctly"
265-
ok "Tools: mimir_recall, mimir_store, mimir_health"
277+
ok "Tools: perseus_vault_recall, perseus_vault_remember, perseus_vault_health"
266278
else
267279
warn "MCP smoke test had issues (non-critical). Manual check:"
268-
warn " Run: mimir --db $MIMIR_DB_PATH"
280+
warn " Run: perseus-vault serve --db $MIMIR_DB_PATH"
269281
fi
270282

271283
# ── Step 7: Success summary ─────────────────────────────────────────────────
272284
header "Success Summary"
273285

274286
echo ""
275-
printf " ${BOLD}%-30s${NC} %s\n" "Mimir version:" "$(mimir --version 2>&1 || echo 'unknown')"
276-
printf " ${BOLD}%-30s${NC} %s\n" "Binary:" "$MIMIR_BIN_DIR/mimir"
287+
printf " ${BOLD}%-30s${NC} %s\n" "Perseus Vault version:" "$(perseus-vault --version 2>&1 || echo 'unknown')"
288+
printf " ${BOLD}%-30s${NC} %s\n" "Binary:" "$MIMIR_BIN_DIR/perseus-vault"
277289
printf " ${BOLD}%-30s${NC} %s\n" "Database:" "$([ -f "$MIMIR_DB_PATH" ] && echo "$MIMIR_DB_PATH" || echo 'created on first serve')"
278290
printf " ${BOLD}%-30s${NC} %s\n" "Data dir:" "$MIMIR_DATA_DIR"
279-
printf " ${BOLD}%-30s${NC} %s\n" "MCP tools:" "mimir_recall, mimir_store, mimir_health"
291+
printf " ${BOLD}%-30s${NC} %s\n" "MCP tools:" "perseus_vault_recall, perseus_vault_remember, perseus_vault_health"
280292
printf " ${BOLD}%-30s${NC} %s\n" "Cargo:" "$(cargo --version 2>&1)"
281293
printf " ${BOLD}%-30s${NC} %s\n" "OS:" "$(uname -s) $(uname -m)"
282294
printf " ${BOLD}%-30s${NC} %s\n" ".env:" "$([ -f "$ENV_FILE" ] && echo '✓ exists' || echo '✗ missing')"
283295

284296
echo ""
285297
echo "============================================"
286-
echo " ${GREEN}Mimir bootstrap complete!${NC}"
298+
echo " ${GREEN}Perseus Vault bootstrap complete!${NC}"
287299
echo ""
288300
echo " Quick commands:"
289-
echo " mimir --db $MIMIR_DB_PATH # Start MCP server"
290-
echo " mimir --version # Show version"
301+
echo " perseus-vault serve --db $MIMIR_DB_PATH # Start MCP server"
302+
echo " perseus-vault --version # Show version"
291303
echo ""
292-
echo " Standalone MCP server:"
293-
echo " mimir --db $MIMIR_DB_PATH"
294-
echo ""
295-
echo " Docs: https://github.com/Perseus-Computing-LLC/mimir"
304+
echo " Docs: https://github.com/Perseus-Computing-LLC/perseus-vault"
296305
echo "============================================"

0 commit comments

Comments
 (0)