Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ OpenUsage lives in your menu bar and shows you how much of your AI coding subscr
- [**MiniMax**](docs/providers/minimax.md) / coding plan session
- [**OpenCode Go**](docs/providers/opencode-go.md) / 5h, weekly, monthly spend limits
- [**Devin**](docs/providers/devin.md) / weekly quota, extra usage
- [**Zed AI**](docs/providers/zed.md) / token spend, edit predictions
- [**Z.ai**](docs/providers/zai.md) / session, weekly, web searches

Community contributions welcome.
Expand Down
15 changes: 14 additions & 1 deletion docs/plugins/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,19 @@ const resp = ctx.host.http.request({

```typescript
host.keychain.readGenericPassword(service: string, account?: string): string
host.keychain.readInternetPassword(server: string, account?: string): { account: string; password: string }
```

Reads a generic password from the macOS Keychain. Pass `account` when the service stores multiple accounts and the plugin must avoid a service-wide match.
Reads passwords from the macOS Keychain. Pass `account` when the service/server stores multiple accounts and the plugin must avoid a broad match.

`readInternetPassword` reads an Internet Password item by server, such as credentials stored for `https://zed.dev`. It returns both the resolved account and password because some apps use the account as part of the API authorization header.

### Behavior

- **macOS only**: Throws on other platforms
- **Throws if not found**: Returns the password string if found, throws otherwise
- **Optional account scope**: When `account` is set, lookup uses both service and account
- **Internet Password account**: When `account` is omitted for `readInternetPassword`, OpenUsage reads the matching keychain item's account attribute and returns it with the password

### Example

Expand All @@ -259,6 +263,15 @@ if (ctx.host.fs.exists("~/.myapp/credentials.json")) {
}
```

```javascript
try {
const item = ctx.host.keychain.readInternetPassword("https://zed.dev")
const authorization = item.account + " " + item.password
} catch {
throw "Login required. Sign in to continue."
}
```

## SQLite

### Query (Read-Only)
Expand Down
7 changes: 6 additions & 1 deletion docs/plugins/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ For each enabled plugin:
-> Inject host APIs (`ctx.host.*`)
-> Evaluate plugin.js
-> Call `probe(ctx)`
-> Parse returned `{ lines: MetricLine[] }`
-> Parse returned `{ lines: MetricLine[], links?: PluginLink[] }`
|
Return `PluginOutput[]` to frontend
|
Expand Down Expand Up @@ -83,6 +83,11 @@ Validation rules:
| `label` | string | Yes | Link text shown in the provider detail quick-actions row |
| `url` | string | Yes | External destination opened in the browser (`http/https` only) |

Plugins can also return `links` from `probe(ctx)` when a quick link depends on the
signed-in account or API response. Runtime links use the same shape and override
manifest links on the detail page. Omit `links` to keep manifest links; return
`links: []` to intentionally show no quick links.

## Output Shape Declaration

Plugins must declare their output shape in `plugin.json`. This enables the UI to render
Expand Down
105 changes: 105 additions & 0 deletions docs/providers/zed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Zed AI

> Reverse-engineered, undocumented API. May change without notice.

## Overview

- **Protocol:** REST (plain JSON)
- **Base URL:** `https://cloud.zed.dev`
- **Auth:** Zed app credentials from the macOS Internet Password keychain item for `https://zed.dev`
- **Authorization header:** `<user_id> <access_token>`
- **Usage:** hosted model token spend and edit predictions

## Scope

This provider tracks Zed-hosted model usage, including Agent Panel and Inline Assistant usage when the selected model provider is Zed-hosted.

It does not track usage for bring-your-own-key model providers or external agents launched from Zed. Those requests are billed by the configured provider/agent directly and are not included in Zed's hosted-model billing response.

## Endpoints

### GET /frontend/billing/usage

Returns the personal billing summary shown by the Zed dashboard.

#### Headers

| Header | Required | Value |
|---|---:|---|
| Authorization | yes | `<user_id> <access_token>` |
| Accept | yes | `application/json` |
| Content-Type | yes | `application/json` |

#### Response

```jsonc
{
"plan": "zed_pro",
"is_account_too_young": false,
"current_usage": {
"token_spend": {
"spend_in_cents": 125,
"limit_in_cents": 500,
"updated_at": "2026-06-01T12:00:00Z"
},
"edit_predictions": {
"used": 120,
"limit": 2000,
"remaining": 1880
}
},
"portal_url": "https://..."
}
```

### GET /frontend/billing/usage/tokens

Returns daily token spend for charting.

```jsonc
{
"usage_by_model": {},
"total_usage": [
{
"date": "2026-06-01",
"tokens": {
"input": 100,
"input_cache_creation": 0,
"input_cache_read": 0,
"output": 25,
"total": 125
},
"cost_in_cents": 10,
"spend_in_cents": 10
}
],
"usage_cache_updated_at": "2026-06-01T12:00:00Z"
}
```

### GET /client/users/me

Fallback endpoint used by the Zed app. It returns account details plus `plan.plan_v3`, `plan.subscription_period`, and `plan.usage.edit_predictions`.

## Authentication

Zed stores production app credentials on macOS as an Internet Password keychain item:

```text
server: https://zed.dev
account: <user_id>
password: <access_token>
```

For local testing or manual setup, OpenUsage also accepts:

```text
ZED_USER_ID=<user_id>
ZED_ACCESS_TOKEN=<access_token>
```

## Notes

- Token spend comes from dashboard billing endpoints when available.
- If dashboard billing endpoints reject the app token or stop responding, OpenUsage falls back to `/client/users/me` and still shows edit prediction usage.
- Organization billing endpoints exist in the dashboard, but this provider currently tracks the signed-in personal account.
1 change: 1 addition & 0 deletions plugins/test-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const makeCtx = () => {
},
keychain: {
readGenericPassword: vi.fn(),
readInternetPassword: vi.fn(),
readGenericPasswordForCurrentUser: vi.fn(),
writeGenericPassword: vi.fn(),
writeGenericPasswordForCurrentUser: vi.fn(),
Expand Down
3 changes: 3 additions & 0 deletions plugins/zed/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading