Documentation
¶
Overview ¶
Package quota is Core/Quota.cs: how much of each AI tool's plan is used. None of them publishes a quota API, so each is read the way the tool itself exposes it, read-only, and nothing leaves the PC except each tool's own usage request with its own sign-in:
Kiro CLI `kiro-cli chat --no-interactive /usage`, the CLI's printed report. Codex the rate-limit snapshot Codex writes into its session logs. Cursor cursor.com/api/usage-summary, with the token Cursor keeps locally. Claude Code api.anthropic.com/api/oauth/usage, with Claude Code's own sign-in.
The parsers here take text and a clock, so they are tested on their own. The readers that touch the disk, the network and kiro-cli are in read.go, and OwlApp's five-minute refresh is schedule.go.
Index ¶
- Constants
- Variables
- func ClaudeHome() string
- func CleanToken(s string) (string, bool)
- func CodexHome() string
- func CursorCookie(token string, utcNow time.Time) (string, bool)
- func CursorDB() string
- func CursorDBUnder(base string) string
- func CursorToken(db string) (*string, error)
- func Custom(v float64, hashes int) string
- func DailyPath() string
- func FormatLocal(t time.Time, pattern string) string
- func ItemShort(id string) string
- func ItemTitle(id string) string
- func KiroRead() (Reading, *KiroUsage)
- func NextReset(text string, today core.Day) (core.Day, bool)
- func ParseTime(s string) (time.Time, bool)
- func RecordDay(path string, u KiroUsage, now time.Time)
- func RunsOut(u KiroUsage, today core.Day) *core.Day
- func SpentBy(days []UsageDay) map[core.Day]Spent
- type Book
- type CreditDay
- type Credits
- type CreditsView
- type KiroUsage
- type Poller
- type Reading
- func ByID(id string) Reading
- func Claude(now time.Time) Reading
- func ClaudeAt(file, url string, now time.Time) Reading
- func ClaudeWith(credentials, url string, now time.Time) Reading
- func Codex(now time.Time) Reading
- func CodexIn(home string, now time.Time) Reading
- func Cursor(now time.Time) Reading
- func CursorAt(db, url string, now time.Time) Reading
- func Fail(why string) Reading
- func Kiro() Reading
- func KiroWith(exe string, args []string, limit time.Duration) Reading
- func ParseClaudeUsage(text string, plan *string, now time.Time) Reading
- func ParseCodexLine(line string, now time.Time) (Reading, bool)
- func ParseCursorSummary(text string) Reading
- func ParseKiro(output string) Reading
- type Scalar
- type ScalarKind
- type SignIn
- type Spent
- type UsageDay
Constants ¶
const ( ItemKiro = "kiro" ItemCodex = "codex" ItemCursor = "cursor" ItemClaude = "claude" )
Notch items: what the resting notch can show, the AI quotas (Core/Layout.cs NotchItem).
const ClaudeKeychainMissing = "Claude Code credentials are unavailable. Sign in and allow Hover to read the Claude Code Keychain entry."
ClaudeKeychainMissing is what the quota says on a Mac when neither the Keychain nor the file gives a sign-in.
const ClaudeKeychainService = "Claude Code-credentials"
ClaudeKeychainService is the Keychain item Claude Code keeps its sign-in in on a Mac: a generic password of this service, whose value is the text .credentials.json holds elsewhere.
const ClaudeURL = "https://api.anthropic.com/api/oauth/usage"
const CreditDays = 30
CreditDays is the days in the view (the longer of Settings' two ranges).
const CursorURL = "https://cursor.com/api/usage-summary"
const Every = 5 * time.Minute
const Tick = 30 * time.Second
Tick is OwlApp's DispatcherTimer.
Variables ¶
var ItemAll = [4]string{ItemClaude, ItemKiro, ItemCodex, ItemCursor}
Functions ¶
func ClaudeHome ¶
func ClaudeHome() string
ClaudeHome is CLAUDE_CONFIG_DIR, else ~/.claude (the same on Windows, Linux and macOS).
func CleanToken ¶
CleanToken is trimmed of white space, then of quotes; false when nothing is left.
func CodexHome ¶
func CodexHome() string
CodexHome is CODEX_HOME, else ~/.codex (the same on Windows, Linux and macOS).
func CursorCookie ¶
CursorCookie: Cursor's web session cookie is "user id::token"; the user id is the last part of the token's subject. False when the token is malformed or about to expire.
func CursorDB ¶
func CursorDB() string
CursorDB is where Cursor (an Electron app) keeps its state: %APPDATA%\Cursor on Windows, ~/Library/Application Support/Cursor on a Mac, $XDG_CONFIG_HOME/Cursor (~/.config/Cursor) on Linux. "" when there is no home to look in.
func CursorDBUnder ¶
CursorDBUnder is Cursor's state database under the folder its Electron shell keeps settings in.
func CursorToken ¶
CursorToken is the token Cursor keeps in its database, as CursorToken reads it: text, or a blob in UTF-16 when its second byte is zero, else UTF-8. Nil for none.
func Custom ¶
Custom is a double through a custom format of "0" and up to hashes "#" decimals ("0", "0.##"). .NET first takes the value to 15 significant digits (the precision it uses for custom formats), then rounds that decimal half away from zero: so 36.5 is "37" and 2.675 is "2.68", where Go's own formatting gives "36" and "2.67".
func FormatLocal ¶
FormatLocal is a .NET date pattern made of d, MMM, HH and mm, in local time. MMM is English (C# uses the current culture's names).
func KiroRead ¶
KiroRead is the reading and the raw credits behind it, made from the one report (it takes eight seconds to print, so the daily credits must not ask twice).
func NextReset ¶
NextReset is the next reset as kiro-cli prints it: "2026-10-01", or "10/01" (this year's, else next year's once it has passed).
func ParseTime ¶
ParseTime is DateTimeOffset.TryParse for the ISO 8601 stamps these tools write: an offset or Z is kept, none means local time (as .NET assumes). The instant, in UTC.
func RecordDay ¶
RecordDay saves a good Kiro reading as today's. Blocks on the disk: called on the poll's goroutine, never the UI's. Written to a temporary file and then renamed over the old one.
func RunsOut ¶
RunsOut is the day the month's credits run out at the month's pace so far (used over the days since the last reset, today counted), if that is before the next reset. Nil with too few days of the month to tell, or no reset date to measure them from.
func SpentBy ¶
SpentBy is each recorded day's credits. Normally the day's last reading less the previous day's. After a monthly reset that is the reading itself. With no previous day, or one that isn't the day before (Hover wasn't running), only the day's own change is known: last less first, and partial. Never negative.
Types ¶
type Book ¶
type Book struct {
// contains filtered or unexported fields
}
Book is the readings and which reads are under way. Pure bookkeeping, so it is tested with a clock of its own.
type CreditDay ¶
CreditDay is one day. Total is nil when there is no reading to tell it from (Hover wasn't running, or the quota is off), and then so is Outside.
type Credits ¶
type Credits struct {
// contains filtered or unexported fields
}
Credits is the latest view, kept up to date on a goroutine of its own. The UI goroutine only reads it.
func NewCredits ¶
func NewCredits(history *core.AgentHistory, file string, changed func()) *Credits
NewCredits makes the view; changed is called on the goroutine, when a new view differs from the last. The goroutine starts at the first View: the background service, which nobody looks at Settings in, never decrypts sessions to count credits.
func (*Credits) OnUsage ¶
OnUsage: a good Kiro reading (on the poll's goroutine): kept as today's, then counted.
func (*Credits) Pin ¶
func (c *Credits) Pin(v CreditsView)
Pin shows this view from now on, whatever the history and the readings say: the screenshots' made-up days.
func (*Credits) Poke ¶
func (c *Credits) Poke()
Poke: the history changed, or Kiro was read: make the view again.
func (*Credits) View ¶
func (c *Credits) View() *CreditsView
View is the latest view; nil until the first is made (the first call starts making it).
type CreditsView ¶
type CreditsView struct {
// Days are the last 30 days, oldest first, those with nothing included.
Days []CreditDay
Today CreditDay
// WeekTotal is the last 7 days' totals (the days with a total), WeekHover Hover's
// share of the 7.
WeekTotal *float64
WeekHover float64
// PerDay7 is the week's total over the days it is known for.
PerDay7 *float64
// Month is the reading of today, i.e. this month so far.
Month *KiroUsage
RunsOut *core.Day
// TopToday is today's dearest sessions in Hover, three at most.
TopToday []core.SessionCredits
}
type KiroUsage ¶
KiroUsage is the raw numbers of kiro-cli's report, which ParseKiro boils down to a percent: what the daily credits are made from. Reset is the text as printed ("10/01" or "2026-10-01"), the next reset.
func ParseKiroUsage ¶
ParseKiroUsage is the credit line, the plan and the reset of the same report, or false when there is no "X of Y covered" (a release that drops it, a failure) or the plan has no credits.
type Poller ¶
type Poller struct {
// contains filtered or unexported fields
}
Poller is the book, the reader and a callback for changes: what OwlApp's quota half is.
func SystemPoller ¶
SystemPoller has the real readers.
func SystemPollerWith ¶
SystemPollerWith has the real readers, and Kiro's raw credits handed on as well, told on the poll's goroutine for every good Kiro reading. They don't ride on Reading: a field there would be carried by the other tools too, who never fill it. The Kiro reader sees them where it parses the report, and the other tools are read as before.
type Reading ¶
Reading is one reading of how much of a plan is used. Used is nil when there is nothing to show; Detail then says why ("kiro-cli not found", "Sign in to Cursor").
func Claude ¶
Claude: on a Mac Claude Code keeps its sign-in in the Keychain, and the file is the fallback; elsewhere it is the file.
func ClaudeAt ¶
ClaudeAt is Claude Code's plan limits, as its /usage shows them, asked of api.anthropic.com with its own sign-in, read-only: the sign-in is never refreshed, which would rotate Claude Code's tokens underneath it.
func ClaudeWith ¶
ClaudeWith is ClaudeAt, with the sign-in's JSON already in hand (from the file or the Keychain).
func Kiro ¶
func Kiro() Reading
Kiro is kiro-cli's own report: `kiro-cli chat --no-interactive /usage`. One deadline of 25 s for the exit and both pipes: a grandchild that inherits stdout can hold it open after kiro-cli itself has gone. On a timeout the whole tree is killed.
func ParseClaudeUsage ¶
ParseClaudeUsage reads the usage answer: five_hour and seven_day, each a utilization in percent and an ISO resets_at (null while the window hasn't begun). The notch shows whichever is closer to the limit, as it does for Codex.
func ParseCodexLine ¶
ParseCodexLine reads one token_count event from a Codex session log. Its rate_limits carry the five-hour window (primary) and the weekly one (secondary). The notch shows whichever is closer to the limit; a window whose reset has passed since the snapshot counts as empty again.
func ParseCursorSummary ¶
ParseCursorSummary reads usage-summary: the plan's percentages are already in percent. Older and team accounts report cents used against a limit instead.
type Scalar ¶
type Scalar struct {
Kind ScalarKind
Text string
Blob []byte
}
type ScalarKind ¶
type ScalarKind int
ScalarKind is what ExecuteScalar hands back, as far as Quota.CursorToken looks at it.
const ( ScalarOther ScalarKind = iota ScalarText ScalarBlob )
type SignIn ¶
SignIn is Claude Code's sign-in from .credentials.json: {"claudeAiOauth": {"accessToken", "expiresAt" (ms), "subscriptionType"}}.
func ClaudeSignIn ¶
type Spent ¶
Spent is what Kiro's account spent on a day, across every client. Partial: only the part of the day Hover saw (the first day, or the one after a day Hover wasn't running).
type UsageDay ¶
type UsageDay struct {
Date core.Day
First, Used float64
Limit float64
Reset, Plan *string
// At is when the latest reading was taken (ISO 8601, local offset).
At string
}
UsageDay is a day's readings: the first (where the day began, as far as Hover saw) and the latest. Reset is kiro-cli's printed next reset ("10/01" or "2026-10-01").
func AddReading ¶
AddReading adds a reading to today's row (or starts it). The first reading of a day stays its First, except after a reset within the day: the counter restarted from nothing, so what it held before doesn't count toward today.