Files
goldbrain/goldbrain-memory.src/skills/goldbrain-memory/scripts/bootstrap.sh
T
2026-06-19 23:03:06 -05:00

98 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# bootstrap.sh — stand up (or repair) an goldbrain vault deterministically.
#
# Idempotent and additive: every write is probe-before-write and NEVER overwrites an
# existing file. The marker (_agent/goldbrain-vault.md) is written LAST, so the vault is
# only flagged "set up" once every piece is in place. Safe to re-run any time — that
# is also the "repair" path (it fills in only what is missing).
#
# All scaffold is resolved relative to THIS script's location, so it works regardless
# of the caller's CWD (fixes the old `@scaffold/...` relative-path assumption).
#
# Usage:
# bootstrap.sh [--dry-run]
#
# Env: GB_BASE, GB_KEY (passed through to goldbrain.sh), GB_TODAY (YYYY-MM-DD for {{DATE}}).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
SCAFFOLD="$SKILL_DIR/scaffold"
GB="$SCRIPT_DIR/goldbrain.sh"
TODAY="${GB_TODAY:-$(date +%Y-%m-%d)}"
DRY=0
[ "${1:-}" = "--dry-run" ] || [ "${1:-}" = "-n" ] && DRY=1
[ -d "$SCAFFOLD" ] || { echo "bootstrap: scaffold not found at $SCAFFOLD" >&2; exit 1; }
[ -x "$GB" ] || chmod +x "$GB" 2>/dev/null || true
say() { echo "bootstrap: $*"; }
exists() { GB_VERIFY=0 "$GB" get "$1" >/dev/null 2>&1; } # 0 = present(200), nonzero = absent/404
# seed VAULT_PATH from LOCAL_FILE (with {{DATE}} substitution), only if absent
seed() {
local vpath="$1" local_file="$2"
if exists "$vpath"; then say "skip (exists) $vpath"; return 0; fi
if [ "$DRY" = "1" ]; then say "would seed $vpath <- ${local_file#$SKILL_DIR/}"; return 0; fi
sed "s/{{DATE}}/$TODAY/g" "$local_file" | GB_VERIFY=1 "$GB" put "$vpath" - >/dev/null
say "seeded $vpath"
}
# write a one-line leaf README only if absent
leaf_readme() {
local dir="$1" name="${1##*/}"
local vpath="$dir/README.md"
if exists "$vpath"; then return 0; fi
if [ "$DRY" = "1" ]; then say "would readme $vpath"; return 0; fi
printf '# %s\n\nMemory vault folder. See the goldbrain-memory plugin for conventions.\n' "$name" \
| GB_VERIFY=0 "$GB" put "$vpath" - >/dev/null
say "readme $vpath"
}
# ---- Pre-flight: is the vault already bootstrapped? --------------------------
if exists "_agent/goldbrain-vault.md"; then
ver="$("$GB" get _agent/goldbrain-vault.md 2>/dev/null | sed -n 's/^schema_version:[[:space:]]*//p' | head -1)"
say "marker present (schema_version=${ver:-unknown}). Running repair pass (fills only missing files)."
CUR_SCHEMA=2
if [ -n "$ver" ] && [ "$ver" -lt "$CUR_SCHEMA" ] 2>/dev/null; then
say "NOTE: schema_version $ver < $CUR_SCHEMA — run migrate.sh before relying on the vault."
fi
fi
# ---- 1. Folder tree (leaf READMEs guarantee non-empty dirs) ------------------
LEAVES=(
inbox/captures inbox/imports inbox/processing-log
journal/daily journal/weekly journal/monthly journal/quarterly journal/annual journal/templates
projects/active projects/incubating projects/on-hold projects/archived
areas/business areas/personal areas/learning areas/systems
resources/concepts resources/references resources/people resources/companies resources/meetings
decisions/by-date
_agent/context _agent/memory/working _agent/memory/episodic _agent/memory/semantic
_agent/sessions _agent/health _agent/templates _agent/heartbeat
_agent/skills/active _agent/skills/archived _agent/locks
)
for d in "${LEAVES[@]}"; do leaf_readme "$d"; done
# ---- 2. Templates (mirror scaffold/templates/ 1:1 into the vault) ------------
if [ -d "$SCAFFOLD/templates" ]; then
while IFS= read -r f; do
rel="${f#$SCAFFOLD/templates/}"
seed "$rel" "$f"
done < <(find "$SCAFFOLD/templates" -type f -name '*.md')
fi
# ---- 3. Anchor seeds (only if absent — never fabricate facts) ----------------
seed "_agent/memory/semantic/operator-preferences.md" "$SCAFFOLD/anchors/operator-preferences.seed.md"
seed "_agent/context/current-context.md" "$SCAFFOLD/anchors/current-context.seed.md"
seed "inbox/captures/inbox.md" "$SCAFFOLD/anchors/inbox.seed.md"
# ---- 4. Vault README (human signpost) ----------------------------------------
seed "README.md" "$SCAFFOLD/README.vault.md"
# ---- 5. Marker (write LAST) --------------------------------------------------
seed "_agent/goldbrain-vault.md" "$SCAFFOLD/goldbrain-vault.md"
say "done (${DRY:+DRY-RUN }$TODAY)."
say "Next: create today's daily note + a bootstrap session log + heartbeat (see SKILL.md First-run trace)."