init-vault

A command that creates the folder structure and starter files for a new knowledge vault. A knowledge vault is a local collection of source files, linked wiki pages, and generated documents.

In plain words
What is it for?
Use it to initialize a new vault at a chosen path.
Why use it?
It gives the other wiki commands the folders and marker files they need before they can run.

Command

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add commands/evb87-tech/corpus/init-vault
Clone the repo
git clone --depth 1 https://github.com/evb87-tech/corpus
Per session 32 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 1,798 The whole file, excluding the scripts and references it only reads on demand.
Security scan C 1 finding. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00032 $0.01798
Opus 5 $0.00016 $0.00899
Sonnet 5 $0.00006 $0.00360
Haiku 4.5 $0.00003 $0.00180

Measured yesterday against content hash 851d965e25a9, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade C, and why

init-vault scanned grade C with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Recursive force deletehighDestructive command

rm -rf with a variable or a broad path is one typo away from removing the wrong tree.

echo " rm -rf '${VAULT_PATH}'"
corpus-core/commands/init-vault.md · 175 lines

How it starts

The opening of the file, as written. The whole thing — 175 lines — stays where its author put it; the contents beside it link to each section on GitHub.

set -euo pipefail
# Defensive glob behavior: empty matches return empty, never error.
shopt -u failglob 2>/dev/null || true
shopt -s nullglob 2>/dev/null || true

# 1. Argument validation FIRST — better UX than reporting an internal failure
#    when the user just typed `/init-vault` with no path.
if [ -z "${ARGUMENTS:-}" ]; then
  echo "Usage: /init-vault <path>"
  echo "Example: /init-vault ~/Documents/my-vault"
  exit 1
fi

# 2. Resolve the corpus-core plugin root + templates dir.
#
# Slash-command bodies execute via BashTool, which does NOT inherit
# CLAUDE_PLUGIN_ROOT from the slash-command harness. Search known install
# locations and validate each candidate by requiring a corpus-core plugin.json.
# This prevents picking up an unrelated `corpus-core/templates/vault` from a
# sibling repo or a stray subdirectory under cwd.
validate_corpus_core() {
  local root="$1"
  [ -d "$root/templates/vault" ] || return 1
  [ -f "$root/.claude-plugin/plugin.json" ] || return 1
  grep -q '"name"[[:space:]]*:[[:space:]]*"corpus-core"' "$root/.claude-plugin/plugin.json" || return 1
}

PLUGIN_ROOT=""

# 2a. Explicit env var (Claude Code sets this for hooks; rarely set in BashTool).
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && validate_corpus_core "$CLAUDE_PLUGIN_ROOT"; then
  PLUGIN_ROOT="$CLAUDE_PLUGIN_ROOT"
fi

# 2b. Marketplace cache, picking the LATEST version (sort -V).
if [ -z "$PLUGIN_ROOT" ]; then
  cache_matches=( "$HOME/.claude/plugins/cache/corpus/corpus-core"/*/templates/vault )
  if [ ${#cache_matches[@]} -gt 0 ]; then
    while IFS= read -r path; do
      candidate="$(cd "$path/../.." && pwd)"
      if validate_corpus_core "$candidate"; then
        PLUGIN_ROOT="$candidate"
        break
      fi
    done < <(printf '%s\n' "${cache_matches[@]}" | sort -V -r)
  fi
fi

# 2c. Marketplace clone (unversioned).
if [ -z "$PLUGIN_ROOT" ]; then
  candidate="$HOME/.claude/plugins/marketplaces/corpus/corpus-core"
  if validate_corpus_core "$candidate"; then
    PLUGIN_ROOT="$candidate"
  fi
fi

# 2d. Local dev: only when invoked from inside the corpus repo itself.
#     We REQUIRE the git root to validate as corpus-core, so we never pull
#     templates from an unrelated sibling project.
if [ -z "$PLUGIN_ROOT" ]; then
  git_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
  if [ -n "$git_root" ] && validate_corpus_core "$git_root/corpus-core"; then
    PLUGIN_ROOT="$git_root/corpus-core"
  fi
fi

if [ -z "$PLUGIN_ROOT" ]; then
  echo "Error: cannot locate the corpus-core plugin install."
  echo "  Searched (in order):"
  echo "    1. \$CLAUDE_PLUGIN_ROOT"
  echo "    2. ~/.claude/plugins/cache/corpus/corpus-core/<latest version>/"
  echo "    3. ~/.claude/plugins/marketplaces/corpus/corpus-core/"
  echo "    4. <git repo root>/corpus-core/  (only when run from the corpus repo)"
  echo "  Each candidate must contain templates/vault/ AND .claude-plugin/plugin.json"
  echo "  with \"name\": \"corpus-core\"."
  echo "  Fix: /plugin marketplace update corpus && /plugin install corpus-core@corpus"
  exit 1
fi

TEMPLATES_DIR="$PLUGIN_ROOT/templates/vault"

# 3. Resolve the vault path.
#
# We support `~` and `~/...` (substitute $HOME) and absolute/relative paths.
# We deliberately do NOT support `~user` — the literal string would otherwise
# be silently mangled by ${VAR/#~/$HOME}, producing a wrong path.
case "$ARGUMENTS" in
  "~"|"~/"*)
    VAULT_PATH="${HOME}${ARGUMENTS#\~}"
    ;;
  "~"*)
    echo "Error: ~user expansion is not supported. Use an absolute path or ~/ (your \$HOME)."
    exit 1
    ;;
  *)
    VAULT_PATH="$ARGUMENTS"
    ;;
esac
VAULT_PARENT="$(dirname "$VAULT_PATH")"
VAULT_BASE="$(basename "$VAULT_PATH")"
if [ ! -d "$VAULT_PARENT" ]; then
  echo "Error: parent directory does not exist: $VAULT_PARENT"
  exit 1
fi
VAULT_PATH="$(cd "$VAULT_PARENT" && pwd)/$VAULT_BASE"

# 4. Refuse if a vault already exists at the path.
if [ -f "${VAULT_PATH}/.corpus-vault" ]; then
  echo "Error: vault already exists at ${VAULT_PATH}"
  echo "  Marker: ${VAULT_PATH}/.corpus-vault"
  echo "  Run: export CORPUS_VAULT=${VAULT_PATH}"
  exit 1
fi

# 5. Refuse if the path exists and is non-empty (could be unrelated content,
#    or the rubble of a previous interrupted scaffold).
if [ -d "${VAULT_PATH}" ] && [ -n "$(ls -A "${VAULT_PATH}" 2>/dev/null)" ]; then
  echo "Error: directory not empty and not a corpus vault — pick a fresh path."
  echo "  Path: ${VAULT_PATH}"
  echo "  If a previous /init-vault was interrupted, remove the partial scaffold:"
  echo "    rm -rf '${VAULT_PATH}'"
  exit 1
fi

# 6. Atomic scaffold.
#    Stage in a sibling temp directory (same filesystem → mv is atomic) so
#    a ctrl-C never leaves a half-built vault at the target path.
STAGING="$(mktemp -d "${VAULT_PARENT}/.corpus-vault-staging-XXXXXX")"
# Catch INT/TERM too — bare EXIT does not fire reliably under signals on
# every shell. We always want the staging dir cleaned up.
trap 'rm -rf "$STAGING"' EXIT INT TERM

mkdir -p \
  "$STAGING/raw" \
  "$STAGING/wiki" \
  "$STAGING/output" \
  "$STAGING/.obsidian"

cp -R "${TEMPLATES_DIR}/." "$STAGING/"

# If the target exists (created empty earlier or by a race), remove it first.
# rmdir only succeeds on empty dirs — protects against clobbering content.
if [ -d "$VAULT_PATH" ]; then
  rmdir "$VAULT_PATH" 2>/dev/null || {
    echo "Error: target became non-empty during scaffold: $VAULT_PATH"
    exit 1
  }
fi

mv "$STAGING" "$VAULT_PATH"

# Verify the move landed correctly. If a third party created $VAULT_PATH
# between rmdir and mv, mv would have nested STAGING inside it instead of
# replacing it — detect that and bail loudly rather than leave a malformed
# vault at the path.
if [ ! -f "$VAULT_PATH/.corpus-vault" ]; then
  echo "Error: vault scaffold did not land at expected path (race during mv?)"
  echo "  Path: $VAULT_PATH"
  echo "  Inspect and clean up manually."
  exit 1
fi

trap - EXIT INT TERM

echo "Vault created: ${VAULT_PATH}"
echo "  export CORPUS_VAULT=${VAULT_PATH}"
echo "  Next: /ingest <source>  — drop a file into raw/ first."

Read the full file on GitHub · 175 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday First seen · 175 lines · 32 tokens per session scan C 851d965e25a9

Subscribe to this mod's changes

init-vault is a command published in the GitHub repository evb87-tech/corpus (1 stars, last pushed 4mo ago), licensed MIT. It adds 32 tokens to every session and 1,798 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it C with 1 finding (recursive force delete). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.