Feature: Add usage reset time to status line metadata for customization

Status Closed — not planned
Maintainer reply None cached
Activity 14 comments · opened Sep 5, 2025 · closed Jan 21, 2026

Environment

  • Platform: Anthropic API
  • Claude CLI version: 1.0.102 (Claude Code)
  • Operating System: Linux 6.6.67
  • Terminal: Terminal

Feature Request

Description

Add usage reset time information to the status line metadata so users can customize how and when this information is displayed in their custom status line.

Current Behavior

  • Status line only shows "nearing usage limits" when close to limit
  • Only shows "will reset at 4pm" when limit is actually hit
  • No metadata available for custom status line configuration
  • No visibility into reset time during normal usage

Proposed Behavior

Add usage reset time fields to the status line metadata, such as:

  • usage_reset_time_absolute: "16:00 UTC"
  • usage_reset_time_relative: "2h 34m"
  • usage_reset_timestamp: Unix timestamp for calculations

This would allow users to customize their status line to show this information in their preferred format and timing.

Motivation

Users need:

  • Constant visibility into when usage limits will reset
  • Ability to customize how this information is displayed
  • Control over when this information appears in their status line
  • Consistent access to reset time data, not just when approaching limits

Expected Implementation

Expose usage reset time data in the status line metadata alongside existing fields, enabling users to configure custom status lines that include this information in their preferred format.

Additional Context

This would provide the underlying data for users to create custom status line configurations showing usage reset information proactively, rather than only seeing reactive warnings when limits are approached or exceeded.

View original on GitHub ↗

14 Comments

github-actions[bot] · 12 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/5621

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

coygeek · 12 months ago

+1 on this feature request. This is a great idea. Having that reset time visible before you hit the limit would be super helpful for pacing usage throughout the day.

While we wait for the Anthropic team to consider this, I stumbled upon a fantastic community project that actually solves this exact problem: ccusage by ryoppippi.

It's a full-blown analysis tool, but it has a dedicated statusline command that provides a ton of real-time info. The output looks like this, and it includes the time remaining in the current 5-hour billing block, which is a perfect way to track this:

🤖 Opus | 💰 $0.23 session / $1.23 today / $0.45 block (2h 45m left) | 🔥 $0.12/hr | 🧠 25,000 (12%)

Setting it up is really straightforward. You just need to add this to your ~/.claude/settings.json (or ~/.config/claude/settings.json):

{
  "statusLine": {
    "type": "command",
    "command": "bunx ccusage statusline",
    "padding": 0
  }
}

(If you don't use bun, you can use npx ccusage@latest statusline instead.)

Anyway, thought I'd share it here as a great temporary fix for anyone else who wants this functionality right now. Hopefully, we'll still see something like this get integrated natively into Claude Code eventually, but this is an amazing community solution in the meantime.

russeg · 12 months ago

Here are some other statuslines

CC should have customized statuslines and advanced reporting, so we won't need external statuslines and that very buggy ccusage

KJ7LNW · 11 months ago

CC does not provide session expiration information in the official status line metadata, so while I certainly use https://github.com/sirmalloc/ccstatusline because it is awesome, there's nothing that it can do.

ccusage must be a different API to get CC usage information?

This issue report is specifically about providing remaining time through the official statusline API, which currently only has the following fields:

{
  "session_id": "35c85168-be6d-47b7-a6c0-a720d0c52172",
  "transcript_path": "/.../35c85168-be6d-47b7-a6c0-a720d0c52172.jsonl",
  "cwd": "/...",
  "model": {
    "id": "claude-opus-4-1-20250805",
    "display_name": "Opus 4.1"
  },
  "workspace": {
    "current_dir": "/...",
    "project_dir": "/..."
  },
  "version": "1.0.102",
  "output_style": {
    "name": "default"
  },
  "cost": {
    "total_cost_usd": 0,
    "total_duration_ms": 722,
    "total_api_duration_ms": 0,
    "total_lines_added": 0,
    "total_lines_removed": 0
  },
  "exceeds_200k_tokens": false
}
KJ7LNW · 11 months ago

this gives me what I want from both statusline and ccusage, but it would still be nice to have the information in the metadata:

STDIN=$(cat)
echo -n "  $(echo "$STDIN" | ccusage statusline | perl -pe 's/^.*\((.*?)\).*$/$1/') |" 
echo "$STDIN" | npx ccstatusline@latest statusline 

produces

  4h 31m left | Model: Sonnet 4  |  Ctx: 0  |  ⎇ main
gm-sp · 11 months ago

With the release of Claude Code v2.0.0 today, there is a new /usage command which provides the percentage of current usage, along with the reset time (for both session + weekly) without any 3rd party tools, and is a very welcomed addition in my eyes.

It would be great to get its metadata into statusline, but currently it is not exposed.

github-actions[bot] · 8 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

KJ7LNW · 8 months ago

Do not autoclose; this needs to be reviewed by a developer

yehudab · 8 months ago

+1 on not closing this issue.
Using /usage in 2.0.x helps, but you need to run it manually from time to time in order to see the current usage percentage and next reset time.
Please expose this information to the status line hook so it can be displayed in custom status lines.

KJ7LNW · 8 months ago

@yehudab , this is my workaround. Feel free to convert it to whichever language you like to use.

#!/usr/bin/env perl
use strict;
use warnings;
use JSON::PP;
use HTTP::Tiny;
use File::Spec;
use Time::Piece;
use Time::Seconds;

# Field name to display label mapping
my %USAGE_LABELS = (
	five_hour => 'Current session',
	seven_day => 'Current week (all models)',
	seven_day_sonnet => 'Current week (Sonnet)',
	seven_day_opus => 'Current week (Opus)',
);

# Fields that always display regardless of utilization
my %ALWAYS_DISPLAY = (
	five_hour => 1,
	seven_day_sonnet => 1,
);

my $BAR_WIDTH = 50;
my $SEPARATOR_WIDTH = $BAR_WIDTH + length("100% used");
my $ANSI_BOLD = "\033[1m";
my $ANSI_RESET = "\033[0m";
my $ANSI_WHITE = "\033[97m";
my $ANSI_WHITE_NORMAL = "\033[37m";
my $ANSI_GREEN = "\033[32m";
my $ANSI_YELLOW = "\033[33m";
my $ANSI_RED = "\033[38;5;88m";

sub read_credentials
{
	my $home = $ENV{HOME};
	unless ($home)
	{
		print "Error: HOME environment variable not set\n";
		return;
	}

	my $credential_path = File::Spec->catfile($home, '.claude', '.credentials.json');

	unless (-f $credential_path)
	{
		print "Error: Credential file not found: $credential_path\n";
		return;
	}

	my $fh;
	unless (open $fh, '<', $credential_path)
	{
		print "Error: Failed to open $credential_path: $!\n";
		return;
	}

	my $content = do { local $/; <$fh> };
	close $fh;

	my $creds = decode_json($content);

	unless (exists $creds->{claudeAiOauth} && exists $creds->{claudeAiOauth}{accessToken})
	{
		print "Error: Missing claudeAiOauth.accessToken in credentials file\n";
		return;
	}

	return $creds->{claudeAiOauth}{accessToken};
}

sub query_usage
{
	my ($token) = @_;

	my $http = HTTP::Tiny->new(
		timeout => 10,
		default_headers => {
			'Accept' => 'application/json',
			'Authorization' => "Bearer $token",
			'anthropic-beta' => 'oauth-2025-04-20',
		},
	);

	my $response = $http->get('https://api.anthropic.com/api/oauth/usage');

	unless ($response->{success})
	{
		print "Error: API request failed: $response->{status} $response->{reason}\n";
		return;
	}

	return decode_json($response->{content});
}

sub get_bar_color
{
	my ($utilization) = @_;

	my $color;
	if ($utilization >= 95)
	{
		$color = $ANSI_RED;
	}
	elsif ($utilization >= 75)
	{
		$color = $ANSI_YELLOW;
	}
	else
	{
		$color = $ANSI_GREEN;
	}

	return $color;
}

sub render_bar
{
	my ($utilization) = @_;

	my $full_blocks = int($utilization / 2);
	my $has_half = ($utilization % 2) == 1;
	my $empty = $BAR_WIDTH - $full_blocks - ($has_half ? 1 : 0);

	my $color = get_bar_color($utilization);

	my $bar = $color . ('█' x $full_blocks);
	$bar .= '▌' if $has_half;
	$bar .= $ANSI_RESET . (' ' x $empty);

	return $bar;
}

sub format_reset_time
{
	my ($reset_at) = @_;

	unless (defined $reset_at)
	{
		return 'unknown';
	}

	unless ($reset_at =~ /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/)
	{
		return $reset_at;
	}

	my $datetime_str = $1;
	my $utc_time = gmtime->strptime($datetime_str, '%Y-%m-%dT%H:%M:%S');
	my $local_time = localtime($utc_time->epoch);

	my $now = localtime;

	my $result;
	if ($local_time->ymd eq $now->ymd)
	{
		$result = $local_time->strftime('%l:%M%P');
	}
	else
	{
		$result = $local_time->strftime('%b %e, %l:%M%P');
	}

	return $result;
}

sub print_usage_field
{
	my ($label, $utilization, $reset) = @_;

	my $bar = render_bar($utilization);
	my $reset_text = "Resets $reset";
	my $usage_text = "$utilization% used";

	my $bar_line_length = $BAR_WIDTH + 1 + length($usage_text);
	my $padding = $bar_line_length - length($label) - length($reset_text);
	$padding = 1 if $padding < 1;

	my $title_line = $ANSI_BOLD . $label . (' ' x $padding) . $reset_text . $ANSI_RESET;

	print "$title_line\n";
	print "$bar $usage_text\n\n";
}

sub display_test_pattern
{
	print $ANSI_WHITE_NORMAL . "Claude Code Usage Test Pattern" . $ANSI_RESET . "\n";
	print "=" x $SEPARATOR_WIDTH . "\n\n";

	print_usage_field("Green (0-74%)", 50, "test");
	print_usage_field("Yellow (75-94%)", 80, "test");
	print_usage_field("Red (95-100%)", 95, "test");
}

sub display_usage
{
	my ($usage) = @_;

	print $ANSI_BOLD . "Claude Code Usage Limits" . $ANSI_RESET . "\n";
	print "=" x $SEPARATOR_WIDTH . "\n\n";

	my @field_order = qw(five_hour seven_day seven_day_sonnet seven_day_opus);

	my %processed;

	for my $field (@field_order)
	{
		next unless exists $usage->{$field} && defined $usage->{$field};

		my $data = $usage->{$field};
		next unless defined $data->{utilization};

		my $utilization = $data->{utilization};
		my $always_display = exists $ALWAYS_DISPLAY{$field};

		next unless $always_display || $utilization > 0;

		my $label = exists $USAGE_LABELS{$field} ? $USAGE_LABELS{$field} : $field;
		my $reset = format_reset_time($data->{resets_at});

		print_usage_field($label, $utilization, $reset);

		$processed{$field} = 1;
	}

	for my $field (sort keys %$usage)
	{
		next if exists $processed{$field};
		next unless defined $usage->{$field};

		my $data = $usage->{$field};
		next unless ref($data) eq 'HASH';
		next unless defined $data->{utilization};

		my $utilization = $data->{utilization};
		next unless $utilization > 0;

		my $label = exists $USAGE_LABELS{$field} ? $USAGE_LABELS{$field} : $field;
		my $reset = format_reset_time($data->{resets_at});

		print_usage_field($label, $utilization, $reset);
	}
}

sub main
{
	if (@ARGV && $ARGV[0] eq '-t')
	{
		display_test_pattern();
		exit 0;
	}

	my $verbose = (@ARGV && $ARGV[0] eq '-v');

	my $token = read_credentials();
	unless (defined $token)
	{
		exit 2;
	}

	my $usage = query_usage($token);
	unless (defined $usage)
	{
		exit 2;
	}

	if ($verbose)
	{
		print JSON::PP->new->pretty->canonical->encode($usage);
		exit 0;
	}

	display_usage($usage);
	exit 0;
}

main();
yehudab · 8 months ago

Thanks @KJ7LNW for the workaround!

I've translated (some of it) to bash and it works well.
For macOS users: Claude Code now stores credentials in the Keychain instead of a JSON file. Here's how to fetch the OAuth token:

keychain_data=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
token=$(echo "$keychain_data" | jq -r '.claudeAiOauth.accessToken')

This can then be used with the API call from the script above.

github-actions[bot] · 7 months ago

This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.

marcindulak · 7 months ago

This issue was closed incorrectly despite recent human comments. This behavior of the bot is reported at https://github.com/anthropics/claude-code/issues/16497. Please upvote that issue, so maybe it gets noticed.

github-actions[bot] · 7 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.