bro — session continuity memory
bro holds the middle layer of state that formal artifacts don't: mood, shortcut vocabulary, live threads, decisions, design tokens, debugging hypotheses, working-discipline rules. This layer is ephemeral in assistant attention but persistent if externalized.
v2.1 architecture: logs live per-repo, always visible at {cwd}/bro/ (the previously-supported hidden .claude/bro/ option was removed in v2.1.1 — single canonical location keeps logs inspectable and removes guessing about where to look). Three-tier layout — repo-wide universals (_principles.md), thread-wide stable context ({tag}/_thread.md), daily ephemeral state ({tag}/{date}.md). Tag derives from chat title (manual rename → AI-generated → first message), with a 6-hex postfix from session UUID for guaranteed uniqueness across parallel chats. Rename-aware: when operator renames a chat, bro detects the change and offers to rename the tag folder. /bro migrate performs LLM-driven semantic conversion of any pre-v2.1 logs into the new format with zero data loss.
Step 0 — installation check (run once per invocation)
Check if this skill lives at the canonical path:
test -f ~/.claude/commands/bro.md && echo canonical || echo other
If file IS at canonical path → proceed to Step 0a.
If file is NOT at canonical path (copied somewhere else, or running inline):
Tell the user:
I notice I'm not installed in the standard location. Claude Desktop / Claude Code auto-discovers skills from
~/.claude/commands/— if I live there,/brobecomes a proper slash command available in every new chat, and updates are easier.Install me to the standard path? I can do it myself — just say yes.
If user confirms:
- Find the current file location (via
findor ask user) mkdir -p ~/.claude/commandscp <current-path> ~/.claude/commands/bro.md- Report: "Done. Restart Claude Desktop and
/browill work from any chat."
If user declines → continue from current location (still works, just not as a slash command).
Step 0a — version check (weekly, non-blocking)
Read ~/.claude/bro-config.json. Check the lastVersionCheck field (ISO timestamp).
If lastVersionCheck is missing or older than 7 days ago:
- Fetch the latest version number from GitHub:
REMOTE_VERSION=$(curl -sfL --max-time 5 \ https://raw.githubusercontent.com/balaka/bro/main/bro.md \ | head -5 | grep "^version:" | awk '{print $2}') - Read installed version from local
bro.mdfrontmatter the same way (path:~/.claude/commands/bro.md). - Compare:
-
Different versions → tell the user:
bro v{REMOTE} available (you have v{LOCAL}). Update? I can fetch it now — just say yes.
Note: if this is a major bump (e.g., v1.x → v2.x), the storage layout changed. v2 stores per-repo (not centralized). v2.1 added LLM-driven migration via
/bro migratethat converts any legacy logs into the new format without data loss.If user confirms → run update flow (Section C). If user declines → proceed; re-check in 7 days.
-
Same version → silent, no interruption.
-
- Write current ISO timestamp to
lastVersionCheckin config so we don't re-check for another 7 days.
Network failure or curl error → silent, skip check, don't block. Try again next time.
Skip version check entirely if env var BRO_NO_UPDATE_CHECK=1 is set.
Step 1 — argument routing
- Argument
setuporconfig→ Section A (configure storage for this repo). - Argument
list→ Section D (list today's threads in this repo). - Argument
update→ Section C (self-update from GitHub). - Argument
migrate→ Section E (LLM-driven migration of legacy logs). - Argument in form
tag=<name>or bare<name>(non-keyword) → Section B with<name>as explicit tag (postfix appended automatically). - No argument → Section B with auto-resolved tag.
Section A — setup flow (storage location for this repo)
v2.1.1 stores per-repo at a single canonical visible location: {cwd}/bro/. The hidden .claude/bro/ alternative was removed in v2.1.1 — single visible path eliminates guessing about where logs live and prevents invisible-storage data loss.
Step 1 — show current state
if [ -d "$(pwd)/bro" ] && [ -f "$(pwd)/bro/.gitignore" ]; then
CURRENT="$(pwd)/bro/"
else
CURRENT="(not configured for this repo)"
fi
Tell user: "Current storage for this repo: {CURRENT}."
Step 1a — migrate hidden .claude/bro/ if it exists (post-v2.1.0 cleanup)
If a .claude/bro/ folder exists from a v2.1.0 install where operator chose hidden:
if [ -d "$(pwd)/.claude/bro" ] && [ -f "$(pwd)/.claude/bro/.gitignore" ]; then
HAS_LEGACY_HIDDEN=1
fi
Detected legacy hidden storage at
{cwd}/.claude/bro/. v2.1.1 uses single visible location{cwd}/bro/. Move existing files to visible location?y / n
If y:
mkdir -p "$(pwd)/bro"
# Move all files (including .gitignore) preserving structure
rsync -a "$(pwd)/.claude/bro/" "$(pwd)/bro/"
rm -rf "$(pwd)/.claude/bro"
Step 2 — check for legacy v1 config
if [ -f ~/.claude/bro-config.json ]; then
LEGACY=$(jq -r '.storageDir // empty' ~/.claude/bro-config.json 2>/dev/null)
fi
If LEGACY is non-empty and not pointing to {cwd}/bro/:
Found legacy v1 storage at
{LEGACY}. v2.1 stores per-repo at{cwd}/bro/. Run/bro migrateto convert any legacy logs into the new three-tier format (zero data loss; originals preserved in_legacy-pre-v2.1/).
Step 3 — confirm location
Storage for this repo will be
{cwd}/bro/.Press Enter to accept, or type a custom path if you have a specific reason (e.g., shared multi-repo workspace).
If user types a path: resolve (~ → $HOME, relative → cwd-relative), use as STORAGE.
Otherwise: STORAGE="{cwd}/bro/".
Single canonical visible path is the design goal — it lets you read logs alongside code without remembering which subfolder. Custom paths are a power-user escape hatch, not a default option.
Step 4 — create storage + .gitignore
mkdir -p "$STORAGE"
cat > "$STORAGE/.gitignore" <<'EOF'
# bro storage — local session memory, not for commit by default.
# Uncomment a line to share repo-wide or thread-wide context with the team:
# !_principles.md
# !*/_thread.md
*
!.gitignore
EOF
Step 5 — optional copy from existing location
If switching from one location to another within the same repo (e.g., user previously had .claude/bro/ and now picks bro/):
Existing storage at
{OLD}has {N} files. Copy_principles.mdand_thread.mdfiles to new location? (Daily logs not copied — they reflect historical state.)y / n
If y: copy _principles.md and */_thread.md to new location (daily files stay at old).
Step 6 — report
bro will store memory for this repo in
{STORAGE}. A.gitignorewas added to keep daily logs local (you can edit it to commit principles/thread files if desired).If you have legacy bro logs (from v1 or v2.0) anywhere on disk, run
/bro migratenext to convert them into the new format.
Section B — normal flow
Step 1 — resolve storage location for this repo
Detection (no per-repo config file — checked by existence). Canonical visible-only path:
CWD=$(pwd)
if [ -d "$CWD/bro" ] && [ -f "$CWD/bro/.gitignore" ]; then
STORAGE="$CWD/bro"
elif [ -d "$CWD/.claude/bro" ] && [ -f "$CWD/.claude/bro/.gitignore" ]; then
# Legacy hidden storage from v2.1.0 — prompt to migrate to visible
echo "Hidden .claude/bro/ detected — Section A Step 1a will offer to move it to canonical visible location."
STORAGE="$CWD/.claude/bro" # use temporarily; setup will migrate next /bro setup
else
# No bro storage in this repo yet → first-time setup
go to Step 1a
fi
If .claude/bro/ is detected, suggest running /bro setup to relocate to canonical `{cwd}