From session-tracker
Use when user asks about session duration, elapsed time, how long they've been working, or "quanto tempo". Also use when any skill or workflow needs to know session elapsed time.
How this skill is triggered — by the user, by Claude, or both
Slash command
/session-tracker:session-statusThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Reports current Claude Code session elapsed time.
Reports current Claude Code session elapsed time.
A SessionStart hook writes $(date +%s) to ~/.claude/session-env/<session_id>/session-tracker. The session ID is stable across compaction, so the timestamp survives context resets. The hook outputs CLAUDE_SESSION_FILE=<path> — use that path in the command below.
UserPromptSubmit/Stop and PreToolUse/PostToolUse hooks append events to
events.log: P <ts> (prompt), T <ts> <tool> / D <ts> <tool> (tool
start/done), S <ts> (stop). Active (working) time is computed additively by
the shared awk that SessionStart deploys to $HOME/.claude/session-env/active-time.awk:
each prompt → stop bracket counts in full, plus up to grace seconds of reading
after each Stop (SESSION_IDLE_THRESHOLD_SECONDS, default 120). A session parked
while you work elsewhere stops accruing after the grace, so the number reflects real
attention rather than wall-clock. Wall-clock elapsed is reported as secondary context.
Run this to get session elapsed time (replace $CLAUDE_SESSION_FILE with the path from the SessionStart hook output):
start=$(cat "$CLAUDE_SESSION_FILE" 2>/dev/null)
if [ -n "$start" ]; then
now=$(date +%s)
elapsed=$((now - start)) # wall-clock (secondary)
grace="${SESSION_IDLE_THRESHOLD_SECONDS:-120}"
EVENTS="$(dirname "$CLAUDE_SESSION_FILE")/events.log"
AWKLIB="$HOME/.claude/session-env/active-time.awk"
active="$elapsed" # fallback when awk/events absent
if [ -f "$EVENTS" ] && [ -f "$AWKLIB" ]; then
active=$(awk -v grace="$grace" -v t_end="$now" -f "$AWKLIB" "$EVENTS")
case "$active" in ''|*[!0-9]*) active="$elapsed" ;; esac
fi
[ "$active" -gt "$elapsed" ] && active="$elapsed"
idle=$((elapsed - active))
fmt() { h=$(( $1 / 3600 )); m=$(( ($1 % 3600) / 60 )); [ "$h" -gt 0 ] && printf '%dh %dm' "$h" "$m" || printf '%dm' "$m"; }
started=$(date -r "$start" "+%H:%M" 2>/dev/null || date -d "@$start" "+%H:%M" 2>/dev/null)
echo "Trabalho: $(fmt "$active") · sessão aberta há $(fmt "$elapsed") (idle $(fmt "$idle"), desde ${started})"
else
echo "Session file not found - hook may not be configured"
fi
After showing the live session, also report today's accumulated total by summing active (working) seconds from $HOME/.claude/session-env/history.jsonl for entries whose start_ts falls on today's local date, and adding the current live active time:
HISTORY="$HOME/.claude/session-env/history.jsonl"
today_past=0
if [ -f "$HISTORY" ]; then
today=$(date +%Y-%m-%d)
today_past=$(jq -s --arg today "$today" '
map(select((.start_ts | strflocaltime("%Y-%m-%d")) == $today))
| map(.active_seconds // 0) | add // 0
' "$HISTORY")
fi
total_today=$((today_past + active))
th=$((total_today / 3600))
tm=$(((total_today % 3600) / 60))
if [ $th -gt 0 ]; then
echo "Trabalho hoje: ${th}h ${tm}m (sessões concluídas + atual)"
else
echo "Trabalho hoje: ${tm}m (sessões concluídas + atual)"
fi
If the session is associated with an issue, include one extra line. Resolution order mirrors the SessionEnd hook:
"$(dirname "$CLAUDE_SESSION_FILE")/issue-tag" exists → Current issue: <KEY>.cwd is a git repo and the current branch matches [A-Z][A-Z0-9_]+-[0-9]+ → Current issue: <KEY> (from branch).TAG_FILE="$(dirname "$CLAUDE_SESSION_FILE")/issue-tag"
if [ -f "$TAG_FILE" ]; then
issue=$(head -n1 "$TAG_FILE" | tr -d '[:space:]')
[ -n "$issue" ] && echo "Current issue: $issue"
elif command -v git >/dev/null 2>&1; then
br=$(git branch --show-current 2>/dev/null || true)
m=$(printf '%s\n' "$br" | grep -oE '[A-Z][A-Z0-9_]+-[0-9]+' | head -n1 || true)
[ -n "$m" ] && echo "Current issue: $m (from branch)"
fi
Display to user:
Trabalho: 1h 50m · sessão aberta há 2h 15m (idle 25m, desde 14:30)
Trabalho hoje: 5h 42m (sessões concluídas + atual)
Current issue: LIN-456
The reading grace after each Stop is configurable via SESSION_IDLE_THRESHOLD_SECONDS (default 120 = 2 minutes). Active time is the headline; wall-clock ("aberta há…") is shown as context only.
If the current session file is missing, inform: session tracking hook not configured. If only the history file is missing, still show the live session and skip the Trabalho hoje line (or show it equal to the live active).
To reset the live timer, tell the user they can use /session-tracker:reset-session or ask naturally.
To see a full worklog, suggest /session-tracker:session-history.
npx claudepluginhub aguinaldotupy/claude-session-tracker --plugin session-trackerCreates bite-sized, testable implementation plans from specs or requirements, with file structure and task decomposition. Activates before coding multi-step tasks.