pack-test
Skill46 starsChanged 7 months agoMITView on GitHub
Test the claude-second-brain npm package by packing it into a tarball and running it via npx. Exercises the full multi-brain scaffold flow end-to-end: scaffolds a brain, verifies config.toml, global skills, and local patches, then scaffolds a second brain to validate config upsert. Trigger phrases: /pack-test, test the package, test the CLI, test the tarball.
- Deletes or force-pushes
In this repository6 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- template/CLAUDE.mdCLAUDE.md
- package-releaseSkill
- releaseSkill
- update-docsSkill
- update-workflowsSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Run each step in order. Stop and report if any step fails.
- Very specific: line 27
If config.toml exists with real brains, back it up so the test cleanup doesn't lose them:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Pack Test
Tests the npm package as it behaves when published. Uses npx to run from the local tarball — pnpm dlx doesn't support local tarball paths (it tries to resolve them as scoped package names). After publishing, pnpm dlx claude-second-brain from the registry works fine.
Multi-brain architecture: brains live at ~/.claude-second-brain/<name>/ and are registered in ~/.claude-second-brain/config.toml. Global skills (~/.claude/skills/brain-*) are plain SKILL.md files with a sibling .csb-version sidecar. They resolve paths at call time via the claude-second-brain path and claude-second-brain qmd subcommands — no paths are baked into the skills themselves.
Important: This test mutates ~/.claude-second-brain/ and ~/.claude/skills/brain-*. If the user has real brains registered, warn them before running — cleanup removes config.toml and the test brains, which does NOT delete their real brain folders but DOES remove their registry entries and overwrite their global skills.
Steps
Run each step in order. Stop and report if any step fails.
Step 1 — Pre-flight: back up existing state
# If the user has existing brains, these are affected:
ls -la ~/.claude-second-brain/ 2>/dev/null || echo "(no existing brains)"
cat ~/.claude-second-brain/config.toml 2>/dev/null || echo "(no existing config)"If config.toml exists with real brains, back it up so the test cleanup doesn't lose them:
cp ~/.claude-second-brain/config.toml ~/.claude-second-brain/config.toml.bak 2>/dev/null || trueStep 2 — Pack
npm packProduces claude-second-brain-<version>.tgz in the repo root. Verify the tarball appears before continuing.
Step 3 — Scaffold first brain
npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz test-brain-aPass test-brain-a as the brain name argument to skip the interactive prompt. Non-TTY stdin skips the GitHub prompt. The brain is created at ~/.claude-second-brain/test-brain-a/.
Assertion: The CLI output should include cd ~/.claude-second-brain/test-brain-a in the Next steps section — not cd test-brain-a.
Step 4 — Verify single-brain scaffold
VAULT_A=~/.claude-second-brain/test-brain-a
# Brain is in the correct location (NOT in CWD)
[ -d "$VAULT_A" ] && echo "PASS: brain at $VAULT_A" || echo "FAIL: brain not at $VAULT_A"
[ ! -d "./test-brain-a" ] && echo "PASS: brain not in CWD" || echo "FAIL: brain leaked into CWD"
# .gitignore renamed from .gitignore.template
[ -f "$VAULT_A/.gitignore" ] && echo "PASS: .gitignore present" || echo "FAIL: .gitignore missing"
# qmd:setup actually created the sqlite db (not just a non-fatal warning)
[ -f "$VAULT_A/.qmd/index.sqlite" ] && echo "PASS: qmd:setup created index.sqlite" || echo "FAIL: qmd:setup did not create .qmd/index.sqlite"
# Wiki stubs, raw-sources dirs, local skills, scripts
ls $VAULT_A/wiki/ $VAULT_A/raw-sources/ $VAULT_A/.claude/skills/ $VAULT_A/scripts/qmd/
# Scripts use a relative .qmd path — no absolute path substitution
grep "\.qmd/index\.sqlite" $VAULT_A/scripts/qmd/setup.ts
grep "\.qmd/index\.sqlite" $VAULT_A/scripts/qmd/reindex.ts
# CLAUDE.md references the relative path too
grep "INDEX_PATH=\.qmd/index\.sqlite" $VAULT_A/CLAUDE.md | head -1
# No lingering tokens anywhere in the vault
! grep -r "__QMD_PATH__\|__CSB_CONFIG__\|__BRAIN_NAME__" $VAULT_A/ 2>/dev/null \
&& echo "PASS: no unpatched tokens" \
|| echo "FAIL: unpatched tokens found above"Step 5 — Verify config.toml was created
CONFIG=~/.claude-second-brain/config.toml
[ -f "$CONFIG" ] && echo "PASS: config.toml created" || echo "FAIL: config.toml missing"
cat $CONFIG
# Assertions on content
grep -q 'default = "test-brain-a"' $CONFIG && echo "PASS: default brain set" || echo "FAIL: default not set"
grep -q 'name = "test-brain-a"' $CONFIG && echo "PASS: brain entry exists" || echo "FAIL: no brain entry"
grep -q "path = \"$HOME/.claude-second-brain/test-brain-a\"" $CONFIG && echo "PASS: path correct" || echo "FAIL: path wrong"
grep -q "qmd_index = \"$HOME/.claude-second-brain/test-brain-a/.qmd/index.sqlite\"" $CONFIG && echo "PASS: qmd_index correct" || echo "FAIL: qmd_index wrong"Step 6 — Verify global skills are CLI-backed
for skill in brain-ingest brain-search brain-refresh; do
FILE=~/.claude/skills/$skill/SKILL.md
SIDECAR=~/.claude/skills/$skill/.csb-version
[ -f "$FILE" ] || { echo "FAIL: $FILE missing"; continue; }
# Must reference the `claude-second-brain` CLI for path / qmd resolution
grep -q "claude-second-brain path" $FILE && echo "PASS: $skill uses \`claude-second-brain path\`" || echo "FAIL: $skill missing CLI path resolution"
grep -q "claude-second-brain qmd" $FILE && echo "PASS: $skill uses \`claude-second-brain qmd\`" || echo "FAIL: $skill missing CLI qmd proxy"
# No lingering tokens, no baked absolute paths
! grep -q "__QMD_PATH__\|__CSB_CONFIG__\|INDEX_PATH=\$QMD_INDEX\|INDEX_PATH=/" $FILE && echo "PASS: $skill clean" || echo "FAIL: $skill still has legacy substitutions"
# Version sidecar exists and matches package version
[ -f "$SIDECAR" ] && echo "PASS: $skill .csb-version present" || echo "FAIL: $skill missing .csb-version"
PKG_VER=$(node -p "require('./package.json').version")
grep -q "\"version\": \"$PKG_VER\"" $SIDECAR && echo "PASS: $skill version matches package" || echo "FAIL: $skill version mismatch"
doneStep 7 — Scaffold second brain (multi-brain upsert test)
npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz test-brain-bStep 8 — Verify config.toml upsert
CONFIG=~/.claude-second-brain/config.toml
cat $CONFIG
# default should STILL be test-brain-a (first brain stays default)
grep -q 'default = "test-brain-a"' $CONFIG && echo "PASS: default unchanged" || echo "FAIL: default was overwritten"
# Both brains should be registered
grep -c '^\[\[brains\]\]' $CONFIG
[ "$(grep -c '^\[\[brains\]\]' $CONFIG)" = "2" ] && echo "PASS: 2 brains registered" || echo "FAIL: expected 2 brain entries"
grep -q 'name = "test-brain-a"' $CONFIG && echo "PASS: brain-a entry exists" || echo "FAIL: brain-a missing"
grep -q 'name = "test-brain-b"' $CONFIG && echo "PASS: brain-b entry exists" || echo "FAIL: brain-b missing"Step 9 — Verify CLI subcommands resolve the default brain
RESOLVED_ROOT=$(npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz path)
[ "$RESOLVED_ROOT" = "$HOME/.claude-second-brain/test-brain-a" ] && echo "PASS: path resolves default brain" || echo "FAIL: path returned '$RESOLVED_ROOT'"
RESOLVED_QMD=$(npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz path --qmd)
[ "$RESOLVED_QMD" = "$HOME/.claude-second-brain/test-brain-a/.qmd/index.sqlite" ] && echo "PASS: path --qmd resolves default brain" || echo "FAIL: path --qmd returned '$RESOLVED_QMD'"
RESOLVED_B=$(npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz path --brain test-brain-b)
[ "$RESOLVED_B" = "$HOME/.claude-second-brain/test-brain-b" ] && echo "PASS: --brain overrides default" || echo "FAIL: --brain returned '$RESOLVED_B'"Step 9b — Verify new CLI surface (v1.1+)
CSB="npx -y claude-second-brain-$(node -p "require('./package.json').version").tgz"
# `csb use` — switch default to brain-b, then back
$CSB use test-brain-b > /dev/null && echo "PASS: csb use test-brain-b" || echo "FAIL: csb use test-brain-b"
grep -q 'default = "test-brain-b"' ~/.claude-second-brain/config.toml && echo "PASS: default switched to brain-b" || echo "FAIL: default did not switch"
$CSB use test-brain-a > /dev/null && echo "PASS: csb use test-brain-a (switch back)" || echo "FAIL: csb use test-brain-a"
grep -q 'default = "test-brain-a"' ~/.claude-second-brain/config.toml && echo "PASS: default back to brain-a" || echo "FAIL: default did not revert"
# `csb path qmd` (positional) should match legacy `csb path --qmd`
POS_QMD=$($CSB path qmd)
LEGACY_QMD=$($CSB path --qmd 2>/dev/null)
[ "$POS_QMD" = "$LEGACY_QMD" ] && [ "$POS_QMD" = "$HOME/.claude-second-brain/test-brain-a/.qmd/index.sqlite" ] \
&& echo "PASS: csb path qmd (positional = legacy flag)" \
|| echo "FAIL: positional='$POS_QMD' legacy='$LEGACY_QMD'"
# `csb path config` (positional) prints central config path
[ "$($CSB path config)" = "$HOME/.claude-second-brain/config.toml" ] && echo "PASS: csb path config" || echo "FAIL: csb path config"
# `csb exec -- pwd` runs inside the resolved brain's root
PWD_OUT=$($CSB exec -- pwd)
[ "$PWD_OUT" = "$HOME/.claude-second-brain/test-brain-a" ] && echo "PASS: csb exec -- pwd" || echo "FAIL: csb exec -- pwd returned '$PWD_OUT'"
# `csb doctor` exits 0 on a fresh scaffold
$CSB doctor > /dev/null 2>&1 && echo "PASS: csb doctor exits 0" || echo "FAIL: csb doctor exited non-zero"
# Per-subcommand --help routes to topic help instead of falling through to createBrain
$CSB rm --help 2>&1 | grep -q "csb rm —" && echo "PASS: csb rm --help" || echo "FAIL: csb rm --help fell through"
$CSB path --help 2>&1 | grep -q "csb path —" && echo "PASS: csb path --help" || echo "FAIL: csb path --help fell through"Step 10 — Final checklist
| Item | Expected | Pass? |
~/.claude-second-brain/test-brain-a/ | Present | |
~/.claude-second-brain/test-brain-b/ | Present | |
| Brain NOT leaked into CWD | ./test-brain-a does not exist | |
.gitignore (not .gitignore.template) | Present in both brains | |
wiki/{index,log,overview}.md, sources/, qa/ | Present in both brains | |
raw-sources/{articles,pdfs,personal}/ | Present in both brains | |
.claude/skills/ — 5 subdirs | brain-ingest, brain-search, brain-refresh, brain-rebuild, lint | |
scripts/qmd/{setup,reindex}.ts | Present in both brains, DB hardcoded to .qmd/index.sqlite relative | |
CLAUDE.md, mise.toml, package.json | Present in both brains | |
CLAUDE.md INDEX_PATH | Relative INDEX_PATH=.qmd/index.sqlite (no absolute substitution) | |
| No unpatched tokens | No __QMD_PATH__, __CSB_CONFIG__, __BRAIN_NAME__ anywhere in vault | |
~/.claude-second-brain/config.toml | Present with default = "test-brain-a" and 2 [[brains]] entries | |
Global skills (~/.claude/skills/brain-{ingest,search,refresh}/SKILL.md) | Present; reference claude-second-brain path + claude-second-brain qmd; .csb-version sidecar matches package version | |
csb use <name> | Rewrites default = "…" in config.toml | |
csb path qmd (positional) | Equal to csb path --qmd | |
csb path config (positional) | Prints ~/.claude-second-brain/config.toml | |
csb exec -- pwd | Prints the resolved brain's directory | |
csb doctor | Exits 0 on a fresh scaffold | |
csb <subcommand> --help | Each subcommand routes to its own topic help (no fall-through to createBrain) |
Step 11 — Clean up
rm -rf ~/.claude-second-brain/test-brain-a
rm -rf ~/.claude-second-brain/test-brain-b
rm -f ~/.claude-second-brain/config.toml
rm -rf ~/.claude/skills/brain-ingest ~/.claude/skills/brain-search ~/.claude/skills/brain-refresh
rm claude-second-brain-$(node -p "require('./package.json').version").tgz
# Restore backed-up config if it existed
[ -f ~/.claude-second-brain/config.toml.bak ] && mv ~/.claude-second-brain/config.toml.bak ~/.claude-second-brain/config.toml
# Remove the parent dir only if empty
rmdir ~/.claude-second-brain/ 2>/dev/null || true
# Clean up GitHub test repos (if any were created — normally no, since non-TTY skips the prompt)
gh repo delete test-brain-a --yes 2>/dev/null || true
gh repo delete test-brain-b --yes 2>/dev/null || trueNote: If the user had pre-existing
brain-ingest/brain-search/brain-refreshglobal skills from a real vault, they were overwritten by this test. They need to re-runnpx claude-second-brainor manually re-scaffold a brain to restore them. The config backup in Step 1 protects their brain registry but not their global skills.
What failure means
.gitignore.templatepresent instead of.gitignore— npm stripped.gitignorefrom the tarball but the rename inbin/create.jsdidn't fire; check thetry/catchrename block- Brain leaked into CWD —
targetDirinmain()still usesprocess.cwd(); checkbin/create.jsusesjoin(CSB_ROOT, targetName) - Missing skill dirs — template copy failed or
.claude/hidden dir wasn't included; checknpm pack --dry-runoutput npxfails to run the bin — shebang orbinfield inpackage.jsonis wrong; check#!/usr/bin/env nodeon line 1 ofbin/create.js__QMD_PATH__or__CSB_CONFIG__still in any file — those substitutions were removed; any hit means a template file still has a legacy placeholder that should be replaced with a relative path or CLI invocation- Global skills still reference
$QMD_INDEX— the old Brain Discovery preamble wasn't dropped; regenerate from the newtemplate/.claude/skills/brain-*/SKILL.mdsources .csb-versionmissing —installGlobalSkills()didn't write the sidecar; check the sidecar write inbin/create.jsconfig.tomlmissing —writeConfig()not called or failed; check the call at the end ofmain()defaultchanged after second brain was created —writeConfig()upsert logic is overwritingdefault; it should only setdefaultwhen the config file doesn't exist yet- Only one
[[brains]]entry after second scaffold —writeConfig()upsert is replacing instead of appending; check the split/filter/join logic claude-second-brain pathreturns wrong brain —parseConfigregex failing to pick updefault = …(or legacyactive = …); inspect the regex- Note:
pnpm dlxcannot run local tarballs — usenpxfor this test. After publishing,pnpm dlx claude-second-brainfrom the registry works fine.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

