commit 12ba2f2c78139c78d96c01a668b70e22dfdf9aa2 from: mtmn date: Mon Sep 7 20:30:03 2026 UTC declutter quota buffer commit - c8e3c5f06180d15bf331fbefe09eba169f617038 commit + 12ba2f2c78139c78d96c01a668b70e22dfdf9aa2 blob - 65e2267280ea6945baa53e5dcb28b27e683bb5ce blob + 870280a852c9319b649d4f7366ea6ade73a72f2a --- README.md +++ README.md @@ -219,9 +219,9 @@ temporary file. When the editor exits nonzero, `alpaca status. `alpaca` saves each successful request as a JSON transcript in -`$XDG_DATA_HOME/alpaca` or `~/.local/share/alpaca`. `alpaca` writes files with mode -`0600` in a directory with mode `0700`. Each turn sends the whole conversation -as context. +`$XDG_DATA_HOME/alpaca` or `~/.local/share/alpaca`. `alpaca` writes files with +mode `0600` in a directory with mode `0700`. Each turn sends the whole +conversation as context. When the editor is `vim` or `neovim`, `alpaca` keeps one editor open for the whole conversation instead of reopening it each turn. Writing the buffer sends @@ -248,8 +248,8 @@ See `man/alpaca-compose.1`. window as a bar showing the used share, with a countdown to the next reset. Some providers also report a table of per-model counts. -Pick a provider with `-p`. Without it, alpaca reports all providers in one output -and skips the ones it cannot reach: +Pick a provider with `-p`. Without it, `alpaca` reports all providers in one +output and skips the ones it cannot reach: ```sh $ alpaca quota # all providers @@ -292,24 +292,23 @@ account. It needs an Admin API key with the `api.usage `platform.openai.com/settings/organization/admin-keys`. A regular project key, such as `sk-proj-...`, gets a 403. -DeepInfra bills per token or per second, with no fixed quota. alpaca prints +DeepInfra bills per token or per second, with no fixed quota. `alpaca` prints no window for it. It prints the remaining credit as a note. A negative balance is funds ready to spend, and a positive one is money owed. The Ollama provider reports Ollama Cloud usage. It takes the key from `$OLLAMA_API_KEY` and defaults to `https://ollama.com`. You can override this with `$OLLAMA_API_ENDPOINT`. It shows the monthly usage pool as the share of -the plan's credits used, with per-model request counts and any extra spend -beyond the plan. The endpoint reports no reset time, so no reset is shown. -Accounts on the old billing get the 5 hour and weekly windows instead, with -locally computed reset boundaries. +the plan's credits used, and any extra spend beyond the plan. The endpoint +reports no reset time, so no reset is shown. Accounts on the old billing get +the 5 hour and weekly windows instead, with locally computed reset boundaries. The Codex provider reports your ChatGPT plan usage, not organization spend. -alpaca reads the OAuth token the Codex CLI stores in `$CODEX_HOME/auth.json`, +`alpaca` reads the OAuth token the Codex CLI stores in `$CODEX_HOME/auth.json`, defaulting to `~/.codex/auth.json`. Sign in once with `codex` and the report works. `--apikey` replaces that token. The endpoint serves the Codex CLI and the ChatGPT client, so it is not a documented public API and may change -without notice. alpaca prints the 5 hour and weekly windows with their reset +without notice. `alpaca` prints the 5 hour and weekly windows with their reset times, the plan name, and the credits balance when the plan has one. The top-level `base_url` configures the chat endpoint only, so `alpaca quota` @@ -324,7 +323,7 @@ Synthetic, DeepInfra and Ollama also fall back to the nothing more specific names one, because all three double as chat endpoints. Anthropic and OpenAI never serve chat, so they ignore the top-level `apikey` and always need a key from a table or profile. Without a chosen provider, -alpaca resolves each provider key on its own, exactly as an explicit `-p` +`alpaca` resolves each provider key on its own, exactly as an explicit `-p` would. It never sends the top-level `apikey` to all providers. Options: blob - be87851ab36a15e4c8b18a41e58b8a7981938ae5 blob + 7067c3e1bf36af142b3e44c2c51e72410f9d0cba --- man/alpaca-compose.1.scd +++ man/alpaca-compose.1.scd @@ -26,10 +26,10 @@ output out of the pipeline. If there is no controlling inherits the process's streams. Saving an empty buffer sends nothing and ends the session with status 0. -Each successful request is saved as a JSON transcript in _$XDG_DATA_HOME/alpaca_, -or _~/.local/share/alpaca_ when that variable is unset. *alpaca* writes the -transcripts with mode 0600 in a directory with mode 0700. Each turn sends the -whole conversation as context. +Each successful request is saved as a JSON transcript in +_$XDG_DATA_HOME/alpaca_, or _~/.local/share/alpaca_ when that variable is +unset. *alpaca* writes the transcripts with mode 0600 in a directory with mode +0700. Each turn sends the whole conversation as context. When the editor is *vim* or *neovim*, *alpaca* keeps one editor open for the whole conversation instead of reopening it each turn. Writing the buffer @@ -49,7 +49,8 @@ until the reply arrives and reloads the buffer. Classi # Options *-m*, *--model* _model_ - The model to use. It defaults to *ALPACA_MODEL*, or *gpt-4o-mini* if that is not set. + The model to use. It defaults to *ALPACA_MODEL*, or *gpt-4o-mini* if that + is not set. *-s*, *--system* _msg_ The system prompt, sent before the conversation. @@ -58,7 +59,8 @@ until the reply arrives and reloads the buffer. Classi The sampling temperature. *-T*, *--timeout* _secs_ - The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if that is not set. + The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if + that is not set. *--reasoning-effort* _effort_ One of *low*, *medium*, *high* or *none*. @@ -87,13 +89,13 @@ until the reply arrives and reloads the buffer. Classi # Configuration -This command reads its settings from the Alpaca configuration file. +This command reads its settings from the alpaca configuration file. Command-line options and environment variables take priority. See *alpaca-config*(5). # Exit status -An editor that exits non-zero sets the exit status of *alpaca compose*, so +An editor that exits nonzero sets the exit status of *alpaca compose*, so aborting an edit aborts the request. Usage errors exit 2. # Examples blob - 682c73da29d5c26d031ce1a3ba47e72f53941cd6 blob + c681e966e24eb9df81f0c4848ad4f472d17b388c --- man/alpaca-config.5.scd +++ man/alpaca-config.5.scd @@ -6,10 +6,10 @@ alpaca-config - configure default options for alpaca # Description -Alpaca reads shared defaults from _$XDG_CONFIG_HOME/alpaca/config.toml_. If you -do not set *XDG_CONFIG_HOME*, Alpaca reads _~/.config/alpaca/config.toml_. +alpaca reads shared defaults from _$XDG_CONFIG_HOME/alpaca/config.toml_. If you +do not set *XDG_CONFIG_HOME*, alpaca reads _~/.config/alpaca/config.toml_. -The file is optional. Alpaca exits with an error if the file exists but cannot +The file is optional. alpaca exits with an error if the file exists but cannot be read or parsed. Settings take priority in this order: blob - 3054cefdd7e70d720bfe12a8f5da5d42dfc7672f blob + 73d2f1b89863c2428a43fc1e9ec679b4168449f6 --- man/alpaca-quota.1.scd +++ man/alpaca-quota.1.scd @@ -67,11 +67,10 @@ all providers. *ollama* Ollama Cloud. It takes the key from *OLLAMA_API_KEY*. The base URL is *https://ollama.com*, or *$OLLAMA_API_ENDPOINT* when set. It prints the - monthly usage pool as the share of the plan's credits used, a table of - per-model request counts, and any extra spend beyond the plan. It shows - no reset, because the endpoint reports no reset time. Accounts on the - old billing get the 5 hour and weekly windows instead, with locally - computed reset boundaries. + monthly usage pool as the share of the plan's credits used, and any extra + spend beyond the plan. It shows no reset, because the endpoint reports no + reset time. Accounts on the old billing get the 5 hour and weekly windows + instead, with locally computed reset boundaries. The *anthropic* endpoint is not a documented public API, so it may change without notice. It expects the short-lived OAuth token the Claude Code CLI @@ -86,7 +85,8 @@ again. cannot reach. *-T*, *--timeout* _secs_ - The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if that is not set. + The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if + that is not set. *--apikey* _key_ The API key or OAuth token, replacing the provider default. @@ -111,7 +111,7 @@ again. # Configuration -This command uses *output_format* and *timeout* from the Alpaca configuration +This command uses *output_format* and *timeout* from the alpaca configuration file. Top-level *base_url* configures the chat endpoint, so this command never uses it for any provider: each provider already has the correct endpoint built in. A table named after a provider, such as *[anthropic]* or blob - 1c77f2c18a36211a336d9b1aecef268ee748227a blob + 85f0dcefd1e752e0a7d65127804491b6c96c1502 --- man/alpaca.1.scd +++ man/alpaca.1.scd @@ -43,13 +43,15 @@ as in *alpaca -- quota*. # Options *-m*, *--model* _model_ - The model to use. It defaults to *ALPACA_MODEL*, or *gpt-4o-mini* if that is not set. + The model to use. It defaults to *ALPACA_MODEL*, or *gpt-4o-mini* if that + is not set. *-t*, *--temperature* _temp_ The sampling temperature. *-T*, *--timeout* _secs_ - The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if that is not set. + The request timeout in seconds. It defaults to *ALPACA_TIMEOUT*, or 60 if + that is not set. *-s*, *--system* _msg_ The system prompt. It is always sent first. blob - e133bb147b6c894ab6b24ff1746faee228cd1130 blob + 411e416a1df5089621a257b95bdb8789d2ec85a3 --- src/usage/ollama.rs +++ src/usage/ollama.rs @@ -126,13 +126,10 @@ fn build(usage: &Usage, now: DateTime) -> View { rows: sorted(&limits.weekly.models), }); } + // The monthly pool is a credit pool, not a request window: its per-model + // request counts are not shown. if let Some(used) = limits.monthly.usage { windows.push(Window::new("monthly", used, None)); - tables.push(Table { - heading: "monthly models".to_string(), - unit: "reqs", - rows: sorted(&limits.monthly.models), - }); } if !usage.activity.models.is_empty() { tables.push(Table { @@ -262,21 +259,9 @@ mod test { view.windows[0].resets_in_secs, None, "the monthly pool renews on the plan start day, which is not reported" ); - assert_eq!(view.tables.len(), 1); - assert_eq!(view.tables[0].heading, "monthly models"); - assert_eq!( - view.tables[0].rows, - vec![ - ModelCount { - name: "kimi-k3".to_string(), - requests: 329 - }, - ModelCount { - name: "web search".to_string(), - requests: 4 - } - ], - "models are sorted busiest first" + assert!( + view.tables.is_empty(), + "the monthly pool has no per-model table" ); Ok(()) } @@ -308,9 +293,9 @@ mod test { }"#, )?; - assert_eq!(view.tables[0].heading, "monthly models"); - assert_eq!(view.tables[1].heading, "activity models"); - assert_eq!(view.tables[1].rows[0].name, "kimi-k3"); + assert_eq!(view.tables.len(), 1); + assert_eq!(view.tables[0].heading, "activity models"); + assert_eq!(view.tables[0].rows[0].name, "kimi-k3"); Ok(()) } blob - 409a19f4c2734c1d40d110e90edd994f97125775 blob + 43367bb1052185e2fdb34f469619c5a820e8ffe0 --- tests/quota.rs +++ tests/quota.rs @@ -660,8 +660,8 @@ fn ollama_quota_reports_the_monthly_pool_of_the_new_bi predicate::str::contains("ollama cloud usage") .and(predicate::str::contains("monthly")) .and(predicate::str::contains("87.6%")) - .and(predicate::str::contains("monthly models")) - .and(predicate::str::contains("kimi-k3")) + .and(predicate::str::contains("monthly models").not()) + .and(predicate::str::contains("kimi-k3").not()) .and(predicate::str::contains("extra 0.00000 USD")) .and(predicate::str::contains("resets in").not()), );