はじめに
こんにちは。バックエンドエンジニアの齋藤です。
今回は、1on1での気づきをきっかけに、xbarを使ってメニューバーにタスクタイマーを自作したら、目の前の作業に集中しやすくなった話について書きます。
1on1で発覚した「タスクの区切りが大きい」問題
きっかけは1on1でした。1on1をしてくれている方が、Slackの返信が早く、一方で自分のタスクも順調に進めていたので、どうやっているか聞いていくうちに、かなりタスクの区切りが細かい、ということがわかりました。
一方、私はというと...
- 実装の区切りが悪い部分でSlackに返信
- 作業中に別のタスクを思い出しそちらを途中で実施
このように、タスクの区切りが大きいせいで集中力が途切れ、結果的にスイッチングコストが増大し、効率が悪くなっているのではないかという結論になりました。
xbarでタスクタイマー作成
この課題を解決するため、まずはタスクを細かく分割し、目の前のタスクに集中することを意識しました。
その中で、「常に目の前のタスクに意識を向けられるように、メニューバーにタスク名とタイマーを表示するのはどうだろうか?」 と考えました。既存のアプリも探してみましたが、なかなか思ったようなものが見つからず。
以前ポモドーロタイマーは試したことがありましたが、途中でSlackを返したり打ち合わせが入ったりして、結局そのタスクにどれくらいかかったのかわからなくなってしまい、あまりうまくいきませんでした。また、ポモドーロタイマーの場合は時間だけが表示されるものが多いですが、目の前のタスクを意識しやすくするためにメニューバーにタスク名も表示したいと思いました。
ChatGPTに相談して教えてもらったxbarで作成するのが、無料かつ簡単そう。社内で利用申請が通っていたこともあり、xbarで作成してみることにしました。
xbarとは
xbarは、macOSのメニューバーに任意のスクリプトの出力を表示できる無料のツールです。
シェルスクリプトやPythonなどで簡単にウィジェットを作成でき、メニューバーを自分好みにカスタマイズできます。
設定手順
- 公式サイトからxbarをインストール
- plugins フォルダを開く(
/Users/username/Library/Application Support/xbar/plugin) - スクリプトを作成して保存する(内容は後述します。ファイル名例:
current_task.1s.sh) ※ファイル名の2つ目のセクションは更新間隔。1sは1秒間隔。 - 実行権限を付与する(
chmod +x ファイル名) - メニューバーの
xbar > refresh allをクリック
メニューバーに「タスクを入力」が表示されるようになれば完了です。

入力したタスク名と経過時間が表示されます。
![]()
もう一度クリックすると、タスクの変更やクリアなどができます。

シェルスクリプトの内容です。ベースはChatGPTで作成しました。
xbarでは、1行目の出力がメニューバーに、2行目以降はクリックした時に表示されます。
#!/bin/bash
# <xbar.title>Current Task Timer (Dialog)</xbar.title>
# <xbar.version>v1.3</xbar.version>
DATA_FILE="$HOME/.xbar-current-task"
SCRIPT_PATH="$HOME/Library/Application Support/xbar/plugins/current_task.1s.sh"
MAX_LEN=20
PAUSE_FILE="$HOME/.xbar-current-task.paused" # ← 一時停止フラグ+経過秒数を置く
log_task_completion() {
if [[ -f "$DATA_FILE" ]]; then
end_time=$(date +%s)
start=$(cut -d'|' -f1 "$DATA_FILE")
task_name=$(cut -d'|' -f2- "$DATA_FILE")
elapsed=$(( end_time - start ))
# 停止中だったら停止中の値を使う
if [[ -f "$PAUSE_FILE" ]]; then
elapsed=$(cat "$PAUSE_FILE")
fi
log_dir="$HOME/.xbar-current-task-log"
mkdir -p "$log_dir"
log_file="$log_dir/$(date +%Y-%m-%d).log"
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
formatted_time=$(printf "%02d:%02d:%02d" $((elapsed/3600)) $(( (elapsed/60)%60 )) $((elapsed%60)))
echo "$timestamp - [$formatted_time] $task_name" >> "$log_file"
fi
}
# ---------- クリック時の分岐 ----------
case "$1" in
set) # 引数で直接タスク名を登録
log_task_completion
echo "$(date +%s)|$2" > "$DATA_FILE"
rm -f "$PAUSE_FILE"
exit
;;
prompt) # ダイアログで入力
task=$(osascript -e 'text returned of (display dialog "次のタスクを入力してください:" default answer "")')
if [[ -n "$task" ]]; then
"$SCRIPT_PATH" set "$task"
rm -f "$PAUSE_FILE" # ← 追加:一時停止状態を解除
fi
exit
;;
clear) # タスクをクリア → ファイル削除
log_task_completion
rm -f "$DATA_FILE"
rm -f "$PAUSE_FILE"
exit
;;
pause) # 一時停止
if [[ -f "$DATA_FILE" && ! -f "$PAUSE_FILE" ]]; then
start=$(cut -d'|' -f1 "$DATA_FILE")
elapsed=$(( $(date +%s) - start ))
echo "$elapsed" > "$PAUSE_FILE" # 経過秒数を保存
fi
exit
;;
resume) # 再開
if [[ -f "$PAUSE_FILE" && -f "$DATA_FILE" ]]; then
offset=$(cat "$PAUSE_FILE")
task_name=$(cut -d'|' -f2- "$DATA_FILE")
now=$(date +%s)
echo "$((now - offset))|$task_name" > "$DATA_FILE" # 新しい start を再計算
rm -f "$PAUSE_FILE"
fi
exit
;;
esac
# -------------------------------------
# ---------- 未設定時 ----------
if [[ ! -f "$DATA_FILE" ]]; then
# メニューバーに表示する部分(1行目)
echo "🚀 タスクを入力"
# クリック時に表示する部分(2行目以降)
echo "---"
echo "タスクを入力して開始 | bash=\"$SCRIPT_PATH\" param1=prompt terminal=false"
exit
fi
# ---------- 表示部 ----------
# ---------- 表示部 ----------
start=$(cut -d'|' -f1 "$DATA_FILE")
task=$(cut -d'|' -f2- "$DATA_FILE")
if [[ -f "$PAUSE_FILE" ]]; then
elapsed=$(cat "$PAUSE_FILE") # 停止中は固定値
paused=1
else
elapsed=$(( $(date +%s) - start ))
paused=0
fi
formatted_time=$(printf "%02d:%02d:%02d" $((elapsed/3600)) $(((elapsed/60)%60)) $((elapsed%60)))
# タスク名が長すぎる場合は省略
# Python3を使用した確実な日本語文字列処理
short_task=$(python3 -c "
# システムモジュールをインポート(テンプレート)
import sys
# bashの変数\$taskをPythonのtask変数に代入(トリプルクォートで安全に処理)
task = '''$task'''
# bashの変数\$MAX_LEN(20)をPythonのmax_len変数に代入
max_len = $MAX_LEN
# Unicode対応文字数カウントで日本語も正確に1文字として計算
if len(task) > max_len:
# スライス記法で文字列の最初から20文字目まで切り取り
print(task[:max_len])
else:
# 20文字以下の場合は元の文字列をそのまま出力
print(task)
# エラーメッセージを破棄し、Python3が利用できない場合は元のタスク名を使用
" 2>/dev/null || echo "$task")
# メニューバーに表示する部分(1行目)
if [[ $paused -eq 1 ]]; then
printf "🐶%s [%s]\n" "$short_task" "$formatted_time"
else
printf "%s [%s]\n" "$short_task" "$formatted_time"
fi
# クリック時に表示する部分(2行目以降)
echo "---"
echo "タスク名: $short_task"
echo "フルタスク名: $task"
echo "タスクを変更... | bash=\"$SCRIPT_PATH\" param1=prompt terminal=false"
echo "リセット(同名で再開始) | bash=\"$SCRIPT_PATH\" param1=set param2=\"$task\" terminal=false"
if [[ $paused -eq 1 ]]; then
echo "再開 | bash=\"$SCRIPT_PATH\" param1=resume terminal=false"
else
echo "一時停止 | bash=\"$SCRIPT_PATH\" param1=pause terminal=false"
fi
echo "タスクをクリア | bash=\"$SCRIPT_PATH\" param1=clear terminal=false"
メニューバーに他にたくさんのものが表示されていると、表示されないようなので、不要なものは消しました。
工夫した点
xbarの設定にあたっては、以下の点を意識しました。
- タスク名の省略: メニューバーの表示領域には限りがあり、長すぎると表示されなくなることがあったので、20文字以降を省略するように設定しました。
- 停止・再開機能: タスクを一時停止・再開できるようにすることで、急なSlackや打ち合わせなどで作業を停止しても、スムーズに作業に戻れるようにしました。
- タスク完了時のログ出力: 後から振り返ることで、自分の作業時間やタスクの傾向を分析できるように、タスク完了時にログファイルを出力するように設定しました。
xbar導入後の変化
xbarを導入した結果、以下のような効果がありました。
- 目の前のタスクに集中しやすくなった: メニューバーに常にタスク名とタイマーが表示されることで、目の前のタスクに集中できるようになりました。途中で確認したいことを思い出したり、Slackの通知が気になったりしても、「後で対応しよう」と意識的に判断できるようになりました。
- タスクを中断した際も戻って来やすくなった: Slackの返信や打ち合わせでタスクを中断しても、その前にやっていたことが表示されているので、元のタスクに戻りやすくなりました。
- タスク時間の可視化: 今のタスクにどれくらいの時間をかけているか常に意識できるようになったことで、「大変そう」と腰が重かったタスクが意外と早く終わったり、気づいたら長時間1つの作業をしていたりといったことに気づけるようになりました。
これらの効果に加え、xbar導入によって、「自分は意外とタスクの区切りを意識できていなかった」 という新たな発見もありました。今までは無意識のうちにタスクを中断し、別の作業を始めてしまっていたようでした。
まとめ
xbarでのタスクタイマーの作成方法と、利用したことによる効果を紹介しました。
同じようなことでお悩みの方の参考になれば幸いです。
また、この記事は、Tech blog編集部のメンバーが作ってくれた、テックブログインタビューDifyで生成した内容をベースに作成しました。技術広報としてインタビューしてくれるDifyに一緒に構成を考えてもらうことにより、記事を書きやすくなりました。
採用について
askenではエンジニアを絶賛募集中です。
まずはカジュアルにお話しできればと思いますので、ぜひお気軽にご連絡ください!
また、asken techのXアカウントで、askenのテックブログやイベント情報など、エンジニアリングに関する最新情報を発信していますのでぜひフォローお願いします!