Skip to content

Add Ollama Cloud provider - #1173

Merged
robinebers merged 6 commits into
robinebers:mainfrom
tduarte:claude/ollama-cloud-provider-5cbefb
Sep 5, 2026
Merged

Add Ollama Cloud provider#1173
robinebers merged 6 commits into
robinebers:mainfrom
tduarte:claude/ollama-cloud-provider-5cbefb

Conversation

@tduarte

@tduarte tduarte commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Approved issue

Fixes #1066

TL;DR

Adds Ollama Cloud as a provider: session and weekly limit meters, plus a recent activity spend row. It reuses the ed25519 key that ollama signin already links to the user's account, so there is no API key to paste.

What was happening

  • Ollama Cloud usage was only visible on ollama.com/settings, with no way to track it from the menu bar.
  • The earlier approach discussed in Add Ollama Cloud #366 read browser session cookies, which was rejected.
  • docs.ollama.com/api/usage, linked from Ollama Cloud as provider #415, documents per-request timing fields such as eval_count. It is not an account usage API.

What this changes

Adds Sources/OpenUsage/Providers/Ollama/ following docs/adding-a-provider.md: an auth store, a usage client, and a mapper conforming to ProviderRuntime.

Credentials. Ollama writes an ed25519 keypair to ~/.ollama/id_ed25519 on first run, and ollama signin links it to the ollama.com account. OpenUsage reads that key and signs each request the way the Ollama CLI does:

Authorization: <base64 public key>:<base64 signature>

The signature covers <METHOD>,<request-uri>, where the URI carries a ts unix-seconds parameter, so a captured header cannot be replayed. The private key never leaves the machine. OpenSSHEd25519Key is a bounds-checked reader for the unencrypted OpenSSH container, scoped to what Ollama writes.

Endpoints.

Endpoint Purpose
GET https://ollama.com/api/usage Session and weekly meters, recent activity spend
POST https://ollama.com/api/me Plan name (best-effort; failure does not blank the meters)

The usage endpoint is undocumented and backs ollama.com/settings, so every field is read defensively.

Metrics.

Metric Placement
Session (%) Always visible, pinned
Weekly (%) Always visible, pinned
Last 4 Weeks (spend) On Demand

Plan (Free/Pro/Max) renders as the header badge. The spend row is $0.00 on a subscription and carries real amounts for pay-as-you-go.

Also included. Registration in ProviderCatalog (alphabetical tail, after Grok), DefaultLayout, and ErrorCategory; an ollama.svg provider mark; docs/providers/ollama.md; and README entries.

Heads-up

Reset countdown not supported. Ollama reports how much of each window is used but not when the current window started, so supplying the documented window lengths (5h / 7d) as periodDurationMs would render a static "Resets in 5h" that never counts down. Both resetsAt and periodDurationMs are therefore omitted, at the cost of Ollama's /v1/limits entries carrying no windowSeconds, and the cadence is documented in the provider page instead.

Ollama is opt-in. The signing key exists whether or not the user has signed in, so a probe can only report that Ollama is installed, never that Cloud is set up. Rather than auto-enable and greet every local-models user with a Cloud sign-in warning, hasLocalCredentials() returns false and the user turns Ollama on in Customize. This is the one provider that deliberately does not mirror refresh()'s credential sources in its probe, since the local credential cannot answer the question being asked.

Extra usage balance not included. The field mentioned in the issue does not appear in the response on a Pro account. It is a small addition later if someone with purchased extra usage can share their /api/usage payload.

Provider icon. ollama.svg comes from Simple Icons (CC0). Its path uses SVG arc commands, which SVGPath does not parse, so the arcs are converted to cubics. Rendering was verified through the app's own parser.

Tests

Tests/OpenUsageTests/OllamaProviderTests.swift covers:

  • Key parsing, including malformed and truncated input, against a keypair generated in memory per run (no fixture committed).
  • The signing scheme, verifying the signature against the public key.
  • Mapping a live response shape, including the usage-as-fraction conversion.
  • Missing limits as a hard failure; absent meters omitted rather than shown at zero.
  • Auth and HTTP error paths.
  • Mapper line labels matching the widget descriptors, so the two cannot drift.

swift build and swift test pass on this branch rebased onto main: 1,215 tests, 3 skipped, 0 failures. Verified end to end against a live Pro account.

Screenshots

Collapsed Expanded
image image

🤖 Generated with Claude Code

Tracks Ollama Cloud session and weekly limits plus recent activity
spend, using the ed25519 key that `ollama signin` links to an
ollama.com account — so there is no key for the user to paste and no
browser session to reuse.

Requests are signed the way the Ollama CLI signs them: an
`Authorization: <public key>:<signature>` header over
"<METHOD>,<request-uri>", where the URI carries a `ts` unix-seconds
parameter so a captured header cannot be replayed. `GET /api/usage`
supplies the meters and `POST /api/me` the plan name; the latter is
best-effort and never blanks the meters.

The meters carry no reset countdown on purpose. Ollama documents the
window lengths (5 hours, 7 days) but never reports when the current
window started, and a period without a reset date renders as a static
"Resets in 5h" that never counts down — a real-looking countdown built
from guesswork. The window lengths are documented in
docs/providers/ollama.md instead.

The tests build their OpenSSH key in memory rather than carrying a
fixture: a committed PEM is a real private key as far as any secret
scanner is concerned, throwaway or not. Generating it per run also
proves a real round-trip instead of proving one frozen blob still
parses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tduarte
tduarte force-pushed the claude/ollama-cloud-provider-5cbefb branch from 3895461 to 3814d24 Compare August 25, 2026 16:54
cursor[bot]

This comment was marked as duplicate.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

cursor[bot]

This comment was marked as off-topic.

@robinebers robinebers added the needs-provider-demand Provider has not yet proven substantial demand from users label Aug 25, 2026 — with Cursor
@robinebers

Copy link
Copy Markdown
Owner

lol thanks cursor

@robinebers robinebers removed the needs-provider-demand Provider has not yet proven substantial demand from users label Aug 26, 2026
robinebers

This comment was marked as outdated.

@robinebers robinebers left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review

Thanks for putting this together! Reusing the existing Ollama sign-in keeps setup simple, and leaving out reset countdowns that Ollama doesn't provide is the right call.

This looks close to shipping. I found four small fixes worth making before merge.

Small Fixes

  • Make account-info failures visible. If the plan lookup fails, keep the usage meters working—but leave a useful log and a gentle warning instead of silently dropping the plan badge.
  • Tighten the key check. A damaged key file can currently pass validation and then show a misleading “not signed in” message. Check that the public key sent with the request matches the signing key.
  • Don't label free-of-extra-charge activity as “no usage.” A subscriber can use Ollama heavily and still have $0 additional spend. The Last 4 Weeks tooltip should not describe that as an idle period.
  • Add the missing setup step. If OpenUsage checked for Ollama before it was installed, signing in later won't automatically make it appear. Tell users to enable it in Customize.

Product Choices — For the Maintainer

These are recommendations, not approved requirements:

  • Start Ollama as opt-in if Cloud sign-in cannot be detected locally. Installing Ollama for local models alone shouldn't create a Cloud sign-in warning.
  • Keep the proposed metric layout: Session and Weekly enabled, always visible, and pinned; Last 4 Weeks enabled, On Demand, and unpinned. Order: Session → Weekly → Last 4 Weeks.

What Was Checked

  • ✅ Reviewed all 15 changed files and the related app behavior.
  • ✅ Existing tests passed: 1,215 XCTest cases, 3 skipped, plus 3 Swift Testing tests.
  • ✅ Additional temporary tests reproduced the three code issues above.
  • ⚠️ Not checked with a live Ollama account or in the running app. Before shipping, compare a Pro account's meters with Ollama's dashboard and check a signed-out/local-only install.

Suggested next step: make the small fixes, confirm the product choices, then do that quick app check. No high-severity defect was found, and I wouldn't hold this for reset countdowns or extra-usage balances.

AI-assisted review of commit 3814d24.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

This PR has been inactive for 7 days. It will be closed in 3 days unless there is new activity. If this is still relevant, please comment or push an update.

@github-actions github-actions Bot added the stale No recent activity label Sep 2, 2026
@github-actions github-actions Bot removed the stale No recent activity label Sep 4, 2026
tduarte and others added 3 commits September 4, 2026 14:08
Four fixes from the PR review.

Make account-info failures visible. A failing plan lookup was
indistinguishable from an account with no plan: the badge just went
missing. The account call now reports why it failed, so the provider
logs it and carries a warning while the meters still refresh.

Tighten the key check. The outer public key is what the Authorization
header carries, while the signature comes from the seed. A damaged file
pairing an intact private key with a foreign public half parsed fine,
then got rejected by ollama.com as "not signed in" — a dead end, since
signing in again cannot fix a corrupt key file. The two halves are now
checked against each other.

Don't call $0.00 an idle period. The Last 4 Weeks row counts charges
beyond the plan, so a subscriber can use Ollama heavily and still read
$0.00. It is no longer marked as a usage period, which was giving it a
"No usage in this period" hover.

Document the missing setup step. Provider detection runs once, so
installing Ollama after that check has already run won't switch it on;
the provider page now says to enable it in Customize.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Following the review's product recommendation: a machine with Ollama
installed for local models should not get a Cloud sign-in warning.

The signing key is written the first time Ollama runs, whether or not
`ollama signin` ever links it to an ollama.com account, and only the
network knows whether that link exists. Probing the key therefore
answers "is Ollama installed?", not "is Ollama Cloud set up?", and
auto-enabled the provider for every local-models user. The probe now
reports no credentials, so Ollama is turned on in Customize.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tduarte

tduarte commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review — all four fixes are in, plus the opt-in recommendation.

Small fixes

  • Account-info failures are visible now. The account call reports why it failed instead of returning a bare nil, so the provider logs it and carries a warning while the meters still refresh. Previously a failing plan lookup was indistinguishable from an account with no plan.
  • Key check tightened. You were right, and the failure mode was worse than it looked: the outer public key is what the Authorization header carries, while the signature comes from the seed, and the two were never compared. A damaged file signed correctly, got a 401, and surfaced as "not signed in" — which the user can't fix by signing in again. The halves are now checked against each other, so it reports an unusable key instead.
  • $0.00 is no longer called an idle period. Dropped isUsagePeriod from the Last 4 Weeks row: it counts charges beyond the plan, so a subscriber can use Ollama heavily and still read $0.00. The row and the provider page now say "charges beyond your plan" rather than "spend".
  • Setup step added to docs/providers/ollama.md.

Product choices

  • Ollama is now opt-inhasLocalCredentials() returns false, so a machine running local models never gets a Cloud sign-in warning. Worth flagging that this is the one provider that deliberately doesn't mirror refresh()'s credential sources in its probe, since the key exists from Ollama's first run and only the network knows whether it's linked to an account.
  • Metric layout kept as proposed: Session → Weekly → Last 4 Weeks, first two always visible and pinned, Last 4 Weeks On Demand.

Each fix has a regression test that fails without it. Full suite: 1,273 tests, 3 skipped, 0 failures. Also did the live check you flagged as outstanding — rebuilt and ran the app against a Pro account, and the card matches ollama.com.

main is merged in and the branch is conflict-free.

Human TLDR:

I got Claude to fix the issues from the AI review and made some assumptions for the product direction, but happy to realign with you @robinebers, if you would prefer it to work differently.

Cheers,
@tduarte

@tduarte
tduarte requested a review from robinebers September 4, 2026 21:44

@robinebers robinebers left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fixes and the opt-in/default-layout choices look good. The remaining warning for an unreadable plan response can be handled in a follow-up.

@robinebers

Copy link
Copy Markdown
Owner

Thanks for addressing the review and checking the card against a live account. The opt-in behavior and proposed metric layout are good with me; the remaining warning edge case doesn't need to hold up this PR.

Could you send a small follow-up PR for unreadable plan responses? If /api/me returns 200 OK with malformed data, the plan badge currently disappears without a user-visible warning. Keep the usage meters working, but show the same gentle warning used for failed plan requests. Please add a regression test for that case; the existing test covers HTTP 500 but not a successful HTTP response with an unreadable body.

@robinebers
robinebers merged commit 7a23679 into robinebers:main Sep 5, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please add Ollama Cloud as a provider

3 participants