Skip to content

clankercode/claude-inject-idle-time

Repository files navigation

Claude Code Idle Timing Plugin

Claude Code plugin that injects hidden timing context alongside each user message.

Idle note on re-entry plus a live statusline timer tracking elapsed time since Claude's last reply

The plugin adds three fields inside a compact [timing] block:

  • time — local time with explicit UTC offset
  • idle_for — seconds idle since the assistant's last stop
  • last_turn — seconds the previous assistant turn took to run

Each prompt gets a hidden block Claude reads but you never see in your transcript:

[timing]
time=2026-04-17T16:04:19+10:00
idle_for=57.0s
last_turn=88.2s
[/timing]

What It Does

The plugin uses official Claude Code hooks:

  • UserPromptSubmit injects hidden timing context on every prompt
  • UserPromptSubmit also shows a compact TUI note like [after 5m 2s] when the user replies after more than 10 seconds of idle time
  • Stop persists per-session timing state for the next turn
  • PreCompact resets the idle timer when context compaction runs, so the statusline counts from the compaction event rather than the last pre-compact reply

On a fresh session, unavailable prior-turn fields are omitted.

Install via Marketplace

/plugin marketplace add clankercode/claude-inject-idle-time
/plugin install idle-timing@idle-info

Statusline integration (optional)

This plugin ships a composable fragment that prints the elapsed time since the model's last reply. It is meant to be dropped into your existing statusline script, not to replace one.

Run the slash command for a guided paste-ready snippet tailored to your current statusline:

/idle-time-setup

At a minimum you will need to:

  1. Enable periodic refresh in ~/.claude/settings.json:

    { "statusLine": { "refreshInterval": 1 } }
  2. In your statusline script, after you read stdin into a variable (e.g. input=$(cat)), pipe the full stdin JSON to the fragment so it can see the current session_id and model.id:

    idle=$(echo "$input" | node "/path/to/idle-timing/scripts/statusline-fragment.js" 2>/dev/null || true)
    [ -n "$idle" ] && parts+=("$idle")

The fragment prints just the elapsed time (e.g. 45s, 3m 21s, 17m, 1h 23m). Add any prefix or emoji in your own script.

If the current model no longer matches the one that produced the last reply (e.g. you switched with /model), the fragment prints --- instead — the elapsed time is no longer meaningful. The original model's timer resumes if you switch back.

Flags:

  • --session-id <id> — explicit session id; overrides stdin.
  • --model-id <id> — explicit model id; overrides stdin.
  • --drop-seconds-after <seconds> — switch to minute-only formatting at this threshold (default 900, i.e. 15 minutes).

Local Usage

Run Claude Code with the plugin from this repo root:

claude --plugin-dir .

If Claude Code is already running, reload plugins after changes:

/reload-plugins

Validation

Run the automated test suite:

npm test

Validate the plugin structure:

claude plugin validate .

Count the tokens used by the timing block across representative payloads (uses gpt-tokenizer as a BPE proxy):

bun run tokens

Notes

  • The timing block is added as hidden hook context, not visible prompt text.
  • The over-one-minute idle note is emitted as a hook systemMessage so it is visible to the user without being added to the plugin's additionalContext.
  • In v1, idle time is measured from the previous Stop hook timestamp.

About

Claude Code plugin that injects hidden timing context into every user prompt. 42 tokens, local time with UTC offset, idle seconds since last reply, previous turn duration.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors