👉
SwiftBarでMacOSのメニューバーにClaudeCodeのステータスを表示する
このエントリは、次の画像のようにMacOSのメニューバーにClaudeCodeのステータス表示をする設定手順のメモです。
ClaudeCodeの処理中(thinking):


PermissionRequestの回答待ち(paused):

入力待ち(waiting):

利用するツールはClaudeCode, SwiftBar, iTerm2です。
仕組み
全体の仕組みは、以下のグラフのようになります。
- ClaudeCodeのHookで、ステータス(PermissionRequestの回答待ちor処理中or入力待ち)をStatusファイルに出力
- SwiftBarのプラグインが、Statusファイルに監視してメニューバーにステータスを表示
- メニューバーからメニューが選択されたら、該当するセッションのiTerm2のタブをアクティブ化
実装
実装を示します。
ディレクトリ構成
- $HOME
- dotfiles
- swiftbar
- bin
- claude-status-hook
- iterm-activate-session
- plugins
- claude-status.1s.sh
- bin
- swiftbar
- .claude
- settings.json
- dotfiles
ファイルの内容
dotfiles/swiftbar/bin/claude-status-hook
#!/bin/bash
set -euo pipefail
#
# claude-status-hook - Write per-session Claude Code status
#
# Usage:
# echo '{"session_id":"...","cwd":"..."}' | claude-status-hook <thinking|waiting|paused|cleanup>
#
# Reads session_id from stdin JSON (via hooks), writes status to
# /tmp/claude-code-sessions/<session_id>. Used by SwiftBar plugin
# to aggregate status across multiple Claude Code sessions.
STATUS_DIR="/tmp/claude-code-sessions"
STATUS="${1:-}"
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | /usr/bin/jq -r '.session_id // empty')
CWD=$(echo "$INPUT" | /usr/bin/jq -r '.cwd // empty')
[ -z "$SESSION_ID" ] && exit 0
mkdir -p "$STATUS_DIR"
if [ "$STATUS" = "cleanup" ]; then
rm -f "$STATUS_DIR/$SESSION_ID"
else
BRANCH=$(git -C "$CWD" branch --show-current 2>/dev/null || true)
/usr/bin/jq -n --arg status "$STATUS" --arg cwd "$CWD" --arg iterm_session "${ITERM_SESSION_ID:-}" --arg branch "$BRANCH" \
'{status: $status, cwd: $cwd, iterm_session_id: $iterm_session, branch: $branch}' > "$STATUS_DIR/$SESSION_ID"
fi
dotfiles/swiftbar/bin/iterm-activate-session
#!/bin/bash
set -euo pipefail
# iterm-activate-session - Activate an iTerm2 session by its unique ID
#
# Usage: iterm-activate-session <ITERM_SESSION_ID>
SESSION_ID="${1:-}"
[ -z "$SESSION_ID" ] && exit 1
osascript <<EOF
tell application "iTerm"
set found to false
repeat with w in windows
repeat with t in tabs of w
repeat with s in sessions of t
if unique id of s is equal to "$SESSION_ID" then
set found to true
set foundWindow to w
set foundTab to t
set foundSession to s
exit repeat
end if
end repeat
if found then exit repeat
end repeat
if found then exit repeat
end repeat
if found then
set index of foundWindow to 1
tell foundWindow to select foundTab
activate
end if
end tell
EOF
dotfiles/swiftbar/plugins/claude-status.1s.sh
#!/bin/bash
# claude-status.1s.sh - Aggregate Claude Code session statuses
STATUS_DIR="/tmp/claude-code-sessions"
NOW=$(date +%s)
STALE_SECONDS=7200 # 2 hours
# Cleanup stale files and count sessions
thinking=0
waiting=0
paused=0
total=0
if [ -d "$STATUS_DIR" ]; then
for f in "$STATUS_DIR"/*; do
[ -f "$f" ] || continue
mtime=$(stat -f %m "$f")
if (( NOW - mtime > STALE_SECONDS )); then
rm -f "$f"
continue
fi
total=$((total + 1))
status=$(/usr/bin/jq -r '.status // empty' "$f" 2>/dev/null)
if [ "$status" = "thinking" ]; then
thinking=$((thinking + 1))
elif [ "$status" = "paused" ]; then
paused=$((paused + 1))
elif [ "$status" = "waiting" ]; then
waiting=$((waiting + 1))
fi
done
fi
# Display
if [ "$total" -eq 0 ]; then
echo "💤"
elif [ "$paused" -gt 0 ]; then
if [ "$total" -eq 1 ]; then
echo "⚠️"
else
echo "⚠️${paused}/${total}"
fi
elif [ "$thinking" -gt 0 ]; then
if [ "$total" -eq 1 ]; then
echo "🤔"
else
echo "🤔 ${thinking}/${total}"
fi
elif [ "$waiting" -gt 0 ]; then
if [ "$total" -eq 1 ]; then
echo "🟢"
else
echo "🟢 ${total}"
fi
else
echo "❓"
fi
# Dropdown menu
echo "---"
if [ "$total" -eq 0 ]; then
echo "No active sessions"
else
for f in "$STATUS_DIR"/*; do
[ -f "$f" ] || continue
session_id=$(basename "$f")
status=$(/usr/bin/jq -r '.status // empty' "$f" 2>/dev/null)
cwd=$(/usr/bin/jq -r '.cwd // empty' "$f" 2>/dev/null)
iterm_session=$(/usr/bin/jq -r '.iterm_session_id // empty' "$f" 2>/dev/null)
branch=$(/usr/bin/jq -r '.branch // empty' "$f" 2>/dev/null)
case "$status" in
thinking) icon="🤔" ;;
paused) icon="⚠️" ;;
waiting) icon="🟢" ;;
*) icon="❓" ;;
esac
dir_name="${cwd##*/}"
label="${icon} ${dir_name}"
[ -n "$branch" ] && label="${label} (${branch})"
if [ -n "$iterm_session" ]; then
iterm_session_short=${iterm_session##*:}
echo "${label} | bash=$HOME/dotfiles/swiftbar/bin/iterm-activate-session param1=${iterm_session_short} terminal=false"
else
echo "${label}"
fi
done
fi
.claude/settings.json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook waiting"
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook cleanup"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook thinking"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook waiting"
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook paused"
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook thinking"
}
]
}
],
"PostToolUseFailure": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook thinking"
}
]
}
],
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "$HOME/dotfiles/swiftbar/bin/claude-status-hook waiting"
}
]
}
]
}
}
設定手順
- ClaudeCode, SwiftBar, iTerm2をインストールします.
- 上記の各ファイルを作成します。bin配下のスクリプトには実行権限を付与します.
- SwiftBarのpluginディレクトリは、
$HOME/dotfiles/swiftbar/bin/pluginsにします.
以上。
Discussion