feat: update agent skill with spaces context

This commit is contained in:
Chadpiha
2026-07-24 18:47:11 -07:00
parent 875277d590
commit 6ab13b3fc9
+73 -13
View File
@@ -1,6 +1,6 @@
---
name: openwhispr-api
description: Use this skill when building integrations with the OpenWhispr REST API, calling OpenWhispr endpoints, managing notes/folders/transcriptions programmatically, or connecting to the OpenWhispr MCP server. Covers authentication, all V1 endpoints, pagination, rate limits, error handling, and the remote MCP server.
description: Use this skill when building integrations with the OpenWhispr REST API, calling OpenWhispr endpoints, managing notes/folders/transcriptions programmatically, accessing team-space content with workspace keys, or connecting to the OpenWhispr MCP server. Covers authentication, all V1 endpoints, spaces, pagination, rate limits, error handling, and the remote MCP server.
---
# OpenWhispr API v1
@@ -15,12 +15,19 @@ Pass the API key as a Bearer token in the `Authorization` header on every reques
Authorization: Bearer owk_live_YOUR_KEY
```
Generate keys from the OpenWhispr desktop app under **Settings > API Keys**. Keys start with `owk_live_` and are shown once at creation.
There are two kinds of key:
- **Personal keys** (`owk_live_`) — access your own private notes, folders, and transcriptions. Generated under **Settings > API Keys**.
- **Workspace keys** (`ow_wks_live_`) — access a workspace's **team spaces**. Generated by a workspace admin under **Settings > Workspace > Developer**.
Both are shown once at creation.
### Scopes
Each key has scoped permissions. The API rejects requests missing the required scope with `403 Forbidden`.
**Personal key scopes:**
| Scope | Grants |
| --------------------- | ------------------------------------------------- |
| `notes:read` | List, get, and search notes. List folders. |
@@ -28,6 +35,28 @@ Each key has scoped permissions. The API rejects requests missing the required s
| `transcriptions:read` | List and get transcriptions. |
| `usage:read` | Read usage statistics. |
**Workspace key scopes:**
| Scope | Grants |
| ------------------------------- | ------------------------------------------------------------------------------- |
| `workspace:notes:read` | List, get, and search team-space notes. |
| `workspace:notes:write` | Create, update, and delete team-space notes. |
| `workspace:folders:read` | List team-space folders. |
| `workspace:folders:write` | Create team-space folders. |
| `workspace:transcriptions:read` | Space discovery only for now — no transcription endpoints accept workspace keys yet. |
| `workspace:*` | All of the above (admin). |
Any of the content scopes above also grants `GET /spaces/list` (space discovery).
### Team spaces
A **space** is a shared container of notes and folders inside a workspace. Personal keys never see team-space content; **workspace keys** do, and always address one space at a time via a `space_id`:
- Discover the spaces a key can reach with `GET /spaces/list`.
- `list`, `create`, and `search` for notes and folders **require** a `space_id` (query param or body field) when called with a workspace key, and reject one when called with a personal key.
- Operations addressed by note id (`GET/PATCH/DELETE /notes/{id}`, `GET /notes/{id}/transcript`) resolve the note's space automatically — no `space_id` needed. A workspace key may act on any note in any of its workspace's spaces.
- `space_id` cannot be changed through the API — a note stays in the space it was created in. Move notes between spaces from the desktop app.
## Base URL
```
@@ -50,7 +79,7 @@ Wrap all responses in a consistent envelope.
{
"data": [{ ... }, { ... }],
"has_more": true,
"next_cursor": "2026-04-15T10:30:00.000Z"
"next_cursor": "opaque-cursor-string"
}
```
@@ -94,14 +123,19 @@ Response headers on every request:
## Pagination
List endpoints use cursor-based pagination. Pass the `next_cursor` value from a previous response as the `cursor` query parameter to fetch the next page. When `has_more` is `false`, there are no more results.
List endpoints use cursor-based pagination. Treat `next_cursor` as an **opaque string**: pass it back verbatim as the `cursor` query parameter to fetch the next page — never parse it. (Notes cursors are base64url-encoded composites; transcription cursors are timestamps. Timestamp cursors issued before the composite format remain accepted.) When `has_more` is `false`, there are no more results. An unparseable cursor returns `400 validation_error`.
```
GET /notes/list?limit=50&cursor=2026-04-15T10:30:00.000Z
GET /notes/list?limit=50&cursor=NEXT_CURSOR_FROM_PREVIOUS_RESPONSE
```
## Endpoints
### Spaces (workspace keys only)
**List Spaces** — `GET /spaces/list`
Scope: any workspace content scope (`workspace:notes:read/write`, `workspace:folders:read/write`, or `workspace:transcriptions:read`). Returns the non-archived team spaces in the key's workspace (`id`, `name`, `slug`, `description`, `emoji`, `created_at`, `updated_at`). Use a returned `id` as the `space_id` on notes/folders requests.
### Notes
**List Notes** — `GET /notes/list`
@@ -110,10 +144,11 @@ GET /notes/list?limit=50&cursor=2026-04-15T10:30:00.000Z
| `limit` | integer | No | 1-100, default 50 |
| `cursor` | string | No | Pagination cursor |
| `folder_id` | UUID | No | Filter by folder |
Scope: `notes:read`
| `space_id` | UUID | Workspace keys | Team space to list. Required for workspace keys; rejected for personal keys. |
Scope: `notes:read` (personal) / `workspace:notes:read` (workspace)
**Get Note** — `GET /notes/{id}`
Scope: `notes:read`. Returns 404 if the note does not exist or is deleted.
Scope: `notes:read` / `workspace:notes:read`. Returns 404 if the note does not exist or is deleted. A workspace key may fetch any note in its workspace's spaces.
**Create Note** — `POST /notes/create`
| Field | Type | Required | Description |
@@ -123,7 +158,8 @@ Scope: `notes:read`. Returns 404 if the note does not exist or is deleted.
| `enhanced_content` | string | No | Cleaned/enhanced version |
| `note_type` | enum | No | `personal` (default), `meeting`, `upload` |
| `folder_id` | UUID | No | Target folder |
Scope: `notes:write`. Returns `201` with the created note.
| `space_id` | UUID | Workspace keys | Team space to create in. Required for workspace keys; rejected for personal keys. |
Scope: `notes:write` / `workspace:notes:write`. Returns `201` with the created note.
**Update Note** — `PATCH /notes/{id}`
| Field | Type | Required | Description |
@@ -132,29 +168,34 @@ Scope: `notes:write`. Returns `201` with the created note.
| `content` | string | No | New content |
| `enhanced_content` | string | No | New enhanced content |
| `folder_id` | UUID | No | Move to folder |
Scope: `notes:write`. All fields optional — only provided fields are updated.
Scope: `notes:write` / `workspace:notes:write`. All fields optional — only provided fields are updated. Cannot change a note's space.
**Delete Note** — `DELETE /notes/{id}`
Scope: `notes:write`. Soft-deletes the note. Returns `204 No Content`.
Scope: `notes:write` / `workspace:notes:write`. Soft-deletes the note. Returns `204 No Content`.
**Search Notes** — `POST /notes/search`
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `query` | string | Yes | Search text (1-500 chars) |
| `limit` | integer | No | 1-50, default 20 |
Scope: `notes:read`. Uses hybrid semantic (vector) + full-text search with relevance scoring. Costs 5x against rate limit.
| `space_id` | UUID | Workspace keys | Team space to search. Required for workspace keys; rejected for personal keys. |
Scope: `notes:read` / `workspace:notes:read`. Uses hybrid semantic (vector) + full-text search with relevance scoring. Costs 5x against rate limit.
### Folders
**List Folders** — `GET /folders/list`
Scope: `notes:read`. Returns all folders sorted by `sort_order` then `created_at`.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `space_id` | UUID | Workspace keys | Team space to list. Required for workspace keys; rejected for personal keys. |
Scope: `notes:read` / `workspace:folders:read`. Returns all folders sorted by `sort_order` then `created_at`.
**Create Folder** — `POST /folders/create`
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Folder name (1-100 chars) |
| `sort_order` | integer | No | Sort position |
Scope: `notes:write`. Max 50 folders per user. Returns `409` if name already exists.
| `space_id` | UUID | Workspace keys | Team space to create in. Required for workspace keys; rejected for personal keys. |
Scope: `notes:write` / `workspace:folders:write`. Max 50 folders per user. Returns `409` if name already exists.
### Transcriptions
@@ -260,3 +301,22 @@ done
curl -H "Authorization: Bearer owk_live_YOUR_KEY" \
https://api.openwhispr.com/api/v1/usage
```
### Work with team spaces (workspace key)
```bash
# 1. Discover the spaces this workspace key can reach
curl -H "Authorization: Bearer ow_wks_live_YOUR_KEY" \
https://api.openwhispr.com/api/v1/spaces/list
# 2. List notes in a space (space_id is required for workspace keys)
curl -H "Authorization: Bearer ow_wks_live_YOUR_KEY" \
"https://api.openwhispr.com/api/v1/notes/list?space_id=SPACE_UUID&limit=50"
# 3. Create a note in that space
curl -X POST \
-H "Authorization: Bearer ow_wks_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Kickoff notes", "title": "Kickoff", "space_id": "SPACE_UUID"}' \
https://api.openwhispr.com/api/v1/notes/create
```