@qvac/skills 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hash.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Autogenerated by scripts/build.mjs from skills/. Do not edit.
2
- export const SKILLS_HASH = '8357531791b7cdb8'
2
+ export const SKILLS_HASH = '8ce2fae4970bf369'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/skills",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Skills for the QV.AC app — the SKILL.md tree plus a content-addressed bundle of it.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -5,28 +5,28 @@ tools: [exec(osascript)]
5
5
  platform: [darwin]
6
6
  metadata:
7
7
  {
8
- 'openclaw':
9
- {
10
- 'requires': { 'bins': ['osascript'] },
11
- 'setup':
8
+ "openclaw": {
9
+ "requires": {
10
+ "bins": [
11
+ "osascript"
12
+ ]
13
+ },
14
+ "setup": {
15
+ "summary": "Apple Notes works through macOS automation (osascript), which ships with macOS — nothing to install. The first command triggers a one-time permission prompt to let this app control Notes.",
16
+ "routes": [
12
17
  {
13
- 'summary': 'Apple Notes works through macOS automation (osascript), which ships with macOS — nothing to install. The first command triggers a one-time permission prompt to let this app control Notes.',
14
- 'routes':
15
- [
16
- {
17
- 'kind': 'instructions',
18
- 'label': 'Allow Notes automation',
19
- 'description': "macOS asks once for permission to control Notes. Commands fail until it's granted.",
20
- 'steps':
21
- [
22
- 'Use the skill once — macOS shows a permission prompt to allow control of Notes.',
23
- 'Click Allow.',
24
- 'If it was denied, enable it under System Settings → Privacy & Security → Automation.'
25
- ]
26
- }
27
- ]
18
+ "kind": "instructions",
19
+ "label": "Allow Notes automation",
20
+ "description": "macOS asks once for permission to control Notes. Commands fail until it's granted.",
21
+ "steps": [
22
+ "Use the skill once — macOS shows a permission prompt to allow control of Notes.",
23
+ "Click Allow.",
24
+ "If it was denied, enable it under System Settings → Privacy & Security → Automation."
25
+ ]
28
26
  }
27
+ ]
29
28
  }
29
+ }
30
30
  }
31
31
  ---
32
32
 
@@ -6,6 +6,69 @@ platform: [darwin, linux, win32]
6
6
  credentials: [asana_mcp_access_token]
7
7
  allow_list: [https://mcp.asana.com/v2/mcp]
8
8
  mcp_reads: [get_task, get_tasks, get_my_tasks, get_projects, search_tasks, search_objects]
9
+ metadata:
10
+ {
11
+ "openclaw": {
12
+ "setup": {
13
+ "routes": [
14
+ {
15
+ "kind": "oauth",
16
+ "label": "Asana",
17
+ "provider": "asana",
18
+ "credentialKey": "asana_mcp_access_token",
19
+ "description": "Tasks, projects, and comments",
20
+ "helpUrl": "https://app.asana.com/0/my-apps",
21
+ "steps": [
22
+ "Click Connect and approve access in the browser. Approving grants access to the Asana workspace you allow."
23
+ ],
24
+ "configSteps": [
25
+ "[Open the Asana developer console](https://app.asana.com/0/my-apps) and create an MCP app",
26
+ "In OAuth settings, add the exact redirect URI shown below",
27
+ "In \"Manage distribution\", allow the workspace you want this connection to access"
28
+ ],
29
+ "fields": [
30
+ {
31
+ "key": "clientId",
32
+ "label": "Client ID",
33
+ "placeholder": "OAuth client ID from your app"
34
+ },
35
+ {
36
+ "key": "clientSecret",
37
+ "label": "Client Secret",
38
+ "secret": true
39
+ }
40
+ ],
41
+ "oauth": {
42
+ "stateKey": "asana_oauth",
43
+ "authUrl": "https://app.asana.com/-/oauth_authorize",
44
+ "tokenUrl": "https://app.asana.com/-/oauth_token",
45
+ "tokenAuth": "secret-in-body",
46
+ "port": 18981,
47
+ "scopes": [],
48
+ "extraAuthParams": {
49
+ "resource": "https://mcp.asana.com/v2"
50
+ },
51
+ "verify": {
52
+ "url": "https://mcp.asana.com/v2/mcp",
53
+ "method": "POST",
54
+ "body": {
55
+ "jsonrpc": "2.0",
56
+ "id": 1,
57
+ "method": "initialize",
58
+ "params": {
59
+ "protocolVersion": "2025-03-26",
60
+ "capabilities": {},
61
+ "clientInfo": { "name": "qvac", "version": "1.0.0" }
62
+ }
63
+ },
64
+ "reject": [{ "status": [401, 403], "error": "asana_not_mcp_app" }]
65
+ }
66
+ }
67
+ }
68
+ ]
69
+ }
70
+ }
71
+ }
9
72
  ---
10
73
 
11
74
  # Asana
@@ -2,15 +2,66 @@
2
2
  name: gmail
3
3
  description: Read, search, send, and manage Gmail messages and labels via the Gmail REST API.
4
4
  aliases: [inbox, email+send, email+draft, email+reply, email+forward]
5
- tools: [http_request, gmail_send, gmail_draft]
5
+ tools: [http_request, gmail_get, gmail_send, gmail_draft]
6
6
  platform: [darwin, linux, win32]
7
7
  credentials: [gmail_access_token]
8
8
  allow_list: [https://gmail.googleapis.com/gmail/v1/users/me/]
9
+ metadata:
10
+ {
11
+ "openclaw": {
12
+ "setup": {
13
+ "routes": [
14
+ {
15
+ "kind": "oauth",
16
+ "label": "Gmail",
17
+ "provider": "google",
18
+ "credentialKey": "gmail_access_token",
19
+ "description": "Read, search, send, and manage Gmail messages and labels",
20
+ "steps": [
21
+ "Click Connect and approve access in the browser. Approving grants access to your Gmail only.",
22
+ "Each Google skill is connected separately, with its own app and its own approval."
23
+ ],
24
+ "configSteps": [
25
+ "[Open Google Cloud Console](https://console.cloud.google.com/flows/enableapi?apiid=gmail.googleapis.com) to enable the Gmail API",
26
+ "[Open OAuth clients](https://console.cloud.google.com/auth/clients) to create an OAuth client — choose \"Web application\" as the type",
27
+ "[Open OAuth audience](https://console.cloud.google.com/auth/audience) and add your Google account as a test user"
28
+ ],
29
+ "fields": [
30
+ {
31
+ "key": "clientId",
32
+ "label": "Client ID",
33
+ "placeholder": "OAuth client ID from your app"
34
+ },
35
+ {
36
+ "key": "clientSecret",
37
+ "label": "Client Secret",
38
+ "secret": true
39
+ }
40
+ ],
41
+ "oauth": {
42
+ "stateKey": "gmail_oauth",
43
+ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
44
+ "tokenUrl": "https://oauth2.googleapis.com/token",
45
+ "tokenAuth": "secret-in-body",
46
+ "port": 18978,
47
+ "scopes": [
48
+ "https://www.googleapis.com/auth/gmail.modify"
49
+ ],
50
+ "extraAuthParams": {
51
+ "access_type": "offline",
52
+ "prompt": "consent"
53
+ }
54
+ }
55
+ }
56
+ ]
57
+ }
58
+ }
59
+ }
9
60
  ---
10
61
 
11
62
  # Gmail
12
63
 
13
- Use `gmail_send` to send, `gmail_draft` to draft, and `http_request` for everything else (list, search, get, labels, trash). The Gmail credential is attached automatically to every `gmail.googleapis.com` request — **never include an `auth` block**.
64
+ Read with `gmail_get`, send with `gmail_send`, draft with `gmail_draft`. `http_request` is only for list/search, labels and trash. The Gmail credential is attached automatically to every `gmail.googleapis.com` request — **never include an `auth` block**. Never run code.
14
65
 
15
66
  ## Prerequisites
16
67
 
@@ -25,11 +76,13 @@ set the `gmail_access_token` credential.
25
76
 
26
77
  The host is `gmail.googleapis.com` — not `www.googleapis.com`. Send is at `/messages/send`, never `/send`.
27
78
 
28
- ## Common Operations
79
+ ## Read messages
29
80
 
30
- ### List or search messages
81
+ 1. List with `http_request`. Use `q` for Gmail search (`from:`, `subject:`, `is:unread`, `newer_than:7d`, `has:attachment`, `label:work`). Keep `maxResults` ≤ 10. The result is ids only.
82
+ 2. Call `gmail_get` with each `id`. It returns `headers` (From, To, Subject, Date), `snippet` and, with `format: "full"`, `text`.
83
+ 3. Answer from those fields. Never run code.
31
84
 
32
- `messages.list` returns `{id, threadId}` pairs only — no subjects, no snippets. To summarize you need a follow-up `messages.get` per id. Use `q` for Gmail search syntax (`from:`, `subject:`, `is:unread`, `newer_than:7d`, `has:attachment`, `label:work`). Keep `maxResults` ≤ 10.
85
+ `http_request` to list:
33
86
 
34
87
  ```json
35
88
  {
@@ -39,32 +92,15 @@ The host is `gmail.googleapis.com` — not `www.googleapis.com`. Send is at `/me
39
92
  }
40
93
  ```
41
94
 
42
- ### Get a message (metadata)
43
-
44
- For lists and summaries always use `format=metadata` — it skips the body and is far cheaper than `full`.
95
+ `gmail_get` for each id:
45
96
 
46
97
  ```json
47
- {
48
- "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages/{id}",
49
- "method": "GET",
50
- "query": {
51
- "format": "metadata",
52
- "metadataHeaders": "Subject,From,To,Date,Message-ID,References"
53
- }
54
- }
98
+ { "id": "1a0c420faf8b68fe" }
55
99
  ```
56
100
 
57
- ### Get a message (full body)
101
+ Use `format: "full"` only when the user asks what a message says.
58
102
 
59
- Only when the user needs the content. The body is base64url-encoded in `payload.parts[].body.data` (or `payload.body.data`); decode it before presenting. Prefer the `text/plain` part over `text/html`.
60
-
61
- ```json
62
- {
63
- "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages/{id}",
64
- "method": "GET",
65
- "query": { "format": "full" }
66
- }
67
- ```
103
+ ## Common Operations
68
104
 
69
105
  ### Send a message
70
106
 
@@ -90,7 +126,7 @@ Use `gmail_draft` with the same envelope as `gmail_send`.
90
126
 
91
127
  A reply is `gmail_send` with the original's `threadId`, `inReplyTo`, and `references`. Without these Gmail starts a new thread.
92
128
 
93
- 1. Get the original with `format=metadata` and headers `Message-ID,References,Subject,From,Reply-To`; capture its `threadId`.
129
+ 1. `gmail_get` the original; capture its `threadId` and its `Message-ID` and `References` headers.
94
130
  2. Send with `to` <- original From (or Reply-To), `subject` <- `Re: ` + original (don't double-prefix), `inReplyTo` <- original Message-ID, `references` <- original References then that Message-ID. Keep angle brackets.
95
131
 
96
132
  ```json
@@ -127,15 +163,15 @@ System labels: `INBOX`, `UNREAD`, `STARRED`, `IMPORTANT`, `SPAM`, `TRASH`. Mark
127
163
 
128
164
  ## Output Policy
129
165
 
130
- - Lists: up to 5 entries with subject, sender, and a human-readable date. Fetch full bodies only when asked.
131
- - Decode base64 message bodies before presenting; never include raw base64 blobs.
166
+ - Lists: up to 5 entries with subject, sender, and a human-readable date. Fetch `text` only when asked.
132
167
  - Modify/trash: state the user-facing effect ("marked 3 messages as read"), not the label diff.
133
168
  - Confirm destructive or outgoing actions (send, reply, trash) with the user first.
134
169
 
135
170
  ## Common Mistakes
136
171
 
137
172
  - Using `www.googleapis.com` for Gmail, or building send/draft/reply through `http_request` instead of `gmail_send`/`gmail_draft`.
138
- - Treating `messages.list` results as if they had subjects — they need a follow-up `messages.get`.
173
+ - Treating `messages.list` results as if they had subjects — call `gmail_get` for each id.
174
+ - Reading a message through `http_request` or code instead of `gmail_get`.
139
175
  - Replying without `threadId` + `inReplyTo`/`references` — Gmail starts a new thread.
140
176
  - Sending a placeholder (`<RECIPIENT_EMAIL>`, `recipient@example.com`) — the runtime refuses these.
141
177
  - Inventing an address. The runtime refuses any recipient absent from the conversation and from earlier tool results; search Gmail or ask the user.
@@ -66,6 +66,29 @@
66
66
  "url": "https://gmail.googleapis.com/gmail/v1/users/me/drafts",
67
67
  "builder": "gmail-draft"
68
68
  }
69
+ },
70
+ {
71
+ "tool": "gmail_get",
72
+ "description": "Read one Gmail message by id: sender, recipients, subject, date, snippet and, with format \"full\", the message text. Call it for each id that messages.list returned. Never read a message with http_request or code.",
73
+ "parameters": {
74
+ "type": "object",
75
+ "properties": {
76
+ "id": { "type": "string", "description": "Message id from messages.list" },
77
+ "format": {
78
+ "type": "string",
79
+ "enum": ["metadata", "full"],
80
+ "description": "metadata (default) for lists and summaries; full only when the user needs the message text"
81
+ }
82
+ },
83
+ "required": ["id"]
84
+ },
85
+ "request": {
86
+ "method": "GET",
87
+ "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages/{id}",
88
+ "query": { "metadataHeaders": "Subject,From,To,Date,Message-ID,References" },
89
+ "builder": "gmail-get"
90
+ },
91
+ "response": { "decode": "gmail-message" }
69
92
  }
70
93
  ]
71
94
  }
@@ -6,6 +6,57 @@ tools: [http_request, calendar_create_meet_event, calendar_add_meet]
6
6
  platform: [darwin, linux, win32]
7
7
  credentials: [google_calendar_access_token]
8
8
  allow_list: [https://www.googleapis.com/calendar/v3/]
9
+ metadata:
10
+ {
11
+ "openclaw": {
12
+ "setup": {
13
+ "routes": [
14
+ {
15
+ "kind": "oauth",
16
+ "label": "Google Calendar",
17
+ "provider": "google",
18
+ "credentialKey": "google_calendar_access_token",
19
+ "description": "List, create, update, and delete Google Calendar events",
20
+ "steps": [
21
+ "Click Connect and approve access in the browser. Approving grants access to your calendars only.",
22
+ "Each Google skill is connected separately, with its own app and its own approval."
23
+ ],
24
+ "configSteps": [
25
+ "[Open Google Cloud Console](https://console.cloud.google.com/flows/enableapi?apiid=calendar-json.googleapis.com) to enable the Google Calendar API",
26
+ "[Open OAuth clients](https://console.cloud.google.com/auth/clients) to create an OAuth client — choose \"Web application\" as the type",
27
+ "[Open OAuth audience](https://console.cloud.google.com/auth/audience) and add your Google account as a test user"
28
+ ],
29
+ "fields": [
30
+ {
31
+ "key": "clientId",
32
+ "label": "Client ID",
33
+ "placeholder": "OAuth client ID from your app"
34
+ },
35
+ {
36
+ "key": "clientSecret",
37
+ "label": "Client Secret",
38
+ "secret": true
39
+ }
40
+ ],
41
+ "oauth": {
42
+ "stateKey": "google_calendar_oauth",
43
+ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
44
+ "tokenUrl": "https://oauth2.googleapis.com/token",
45
+ "tokenAuth": "secret-in-body",
46
+ "port": 18978,
47
+ "scopes": [
48
+ "https://www.googleapis.com/auth/calendar"
49
+ ],
50
+ "extraAuthParams": {
51
+ "access_type": "offline",
52
+ "prompt": "consent"
53
+ }
54
+ }
55
+ }
56
+ ]
57
+ }
58
+ }
59
+ }
9
60
  ---
10
61
 
11
62
  # Google Calendar
@@ -5,6 +5,58 @@ tools: [http_request, docs_create, docs_append_text]
5
5
  platform: [darwin, linux, win32]
6
6
  credentials: [google_docs_access_token]
7
7
  allow_list: [https://docs.googleapis.com/v1/documents, https://www.googleapis.com/drive/v3/files]
8
+ metadata:
9
+ {
10
+ "openclaw": {
11
+ "setup": {
12
+ "routes": [
13
+ {
14
+ "kind": "oauth",
15
+ "label": "Google Docs",
16
+ "provider": "google",
17
+ "credentialKey": "google_docs_access_token",
18
+ "description": "Create, read, and edit Google Docs documents",
19
+ "steps": [
20
+ "Click Connect and approve access in the browser. Approving grants access to your documents and Drive files only.",
21
+ "Each Google skill is connected separately, with its own app and its own approval."
22
+ ],
23
+ "configSteps": [
24
+ "[Open Google Cloud Console](https://console.cloud.google.com/flows/enableapi?apiid=docs.googleapis.com,drive.googleapis.com) to enable the Google Docs API",
25
+ "[Open OAuth clients](https://console.cloud.google.com/auth/clients) to create an OAuth client — choose \"Web application\" as the type",
26
+ "[Open OAuth audience](https://console.cloud.google.com/auth/audience) and add your Google account as a test user"
27
+ ],
28
+ "fields": [
29
+ {
30
+ "key": "clientId",
31
+ "label": "Client ID",
32
+ "placeholder": "OAuth client ID from your app"
33
+ },
34
+ {
35
+ "key": "clientSecret",
36
+ "label": "Client Secret",
37
+ "secret": true
38
+ }
39
+ ],
40
+ "oauth": {
41
+ "stateKey": "google_docs_oauth",
42
+ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
43
+ "tokenUrl": "https://oauth2.googleapis.com/token",
44
+ "tokenAuth": "secret-in-body",
45
+ "port": 18978,
46
+ "scopes": [
47
+ "https://www.googleapis.com/auth/documents",
48
+ "https://www.googleapis.com/auth/drive"
49
+ ],
50
+ "extraAuthParams": {
51
+ "access_type": "offline",
52
+ "prompt": "consent"
53
+ }
54
+ }
55
+ }
56
+ ]
57
+ }
58
+ }
59
+ }
8
60
  ---
9
61
 
10
62
  # Google Docs
@@ -5,6 +5,57 @@ tools: [http_request, drive_create_folder, drive_trash]
5
5
  platform: [darwin, linux, win32]
6
6
  credentials: [google_drive_access_token]
7
7
  allow_list: [https://www.googleapis.com/drive/v3/]
8
+ metadata:
9
+ {
10
+ "openclaw": {
11
+ "setup": {
12
+ "routes": [
13
+ {
14
+ "kind": "oauth",
15
+ "label": "Google Drive",
16
+ "provider": "google",
17
+ "credentialKey": "google_drive_access_token",
18
+ "description": "Search, list, and manage Google Drive files and folders",
19
+ "steps": [
20
+ "Click Connect and approve access in the browser. Approving grants access to your Drive files only.",
21
+ "Each Google skill is connected separately, with its own app and its own approval."
22
+ ],
23
+ "configSteps": [
24
+ "[Open Google Cloud Console](https://console.cloud.google.com/flows/enableapi?apiid=drive.googleapis.com) to enable the Google Drive API",
25
+ "[Open OAuth clients](https://console.cloud.google.com/auth/clients) to create an OAuth client — choose \"Web application\" as the type",
26
+ "[Open OAuth audience](https://console.cloud.google.com/auth/audience) and add your Google account as a test user"
27
+ ],
28
+ "fields": [
29
+ {
30
+ "key": "clientId",
31
+ "label": "Client ID",
32
+ "placeholder": "OAuth client ID from your app"
33
+ },
34
+ {
35
+ "key": "clientSecret",
36
+ "label": "Client Secret",
37
+ "secret": true
38
+ }
39
+ ],
40
+ "oauth": {
41
+ "stateKey": "google_drive_oauth",
42
+ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
43
+ "tokenUrl": "https://oauth2.googleapis.com/token",
44
+ "tokenAuth": "secret-in-body",
45
+ "port": 18978,
46
+ "scopes": [
47
+ "https://www.googleapis.com/auth/drive"
48
+ ],
49
+ "extraAuthParams": {
50
+ "access_type": "offline",
51
+ "prompt": "consent"
52
+ }
53
+ }
54
+ }
55
+ ]
56
+ }
57
+ }
58
+ }
8
59
  ---
9
60
 
10
61
  # Google Drive
@@ -6,6 +6,58 @@ platform: [darwin, linux, win32]
6
6
  credentials: [google_sheets_access_token]
7
7
  allow_list:
8
8
  [https://sheets.googleapis.com/v4/spreadsheets, https://www.googleapis.com/drive/v3/files]
9
+ metadata:
10
+ {
11
+ "openclaw": {
12
+ "setup": {
13
+ "routes": [
14
+ {
15
+ "kind": "oauth",
16
+ "label": "Google Sheets",
17
+ "provider": "google",
18
+ "credentialKey": "google_sheets_access_token",
19
+ "description": "Create, read, and update Google Sheets spreadsheets",
20
+ "steps": [
21
+ "Click Connect and approve access in the browser. Approving grants access to your spreadsheets and Drive files only.",
22
+ "Each Google skill is connected separately, with its own app and its own approval."
23
+ ],
24
+ "configSteps": [
25
+ "[Open Google Cloud Console](https://console.cloud.google.com/flows/enableapi?apiid=sheets.googleapis.com,drive.googleapis.com) to enable the Google Sheets API",
26
+ "[Open OAuth clients](https://console.cloud.google.com/auth/clients) to create an OAuth client — choose \"Web application\" as the type",
27
+ "[Open OAuth audience](https://console.cloud.google.com/auth/audience) and add your Google account as a test user"
28
+ ],
29
+ "fields": [
30
+ {
31
+ "key": "clientId",
32
+ "label": "Client ID",
33
+ "placeholder": "OAuth client ID from your app"
34
+ },
35
+ {
36
+ "key": "clientSecret",
37
+ "label": "Client Secret",
38
+ "secret": true
39
+ }
40
+ ],
41
+ "oauth": {
42
+ "stateKey": "google_sheets_oauth",
43
+ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
44
+ "tokenUrl": "https://oauth2.googleapis.com/token",
45
+ "tokenAuth": "secret-in-body",
46
+ "port": 18978,
47
+ "scopes": [
48
+ "https://www.googleapis.com/auth/spreadsheets",
49
+ "https://www.googleapis.com/auth/drive"
50
+ ],
51
+ "extraAuthParams": {
52
+ "access_type": "offline",
53
+ "prompt": "consent"
54
+ }
55
+ }
56
+ }
57
+ ]
58
+ }
59
+ }
60
+ }
9
61
  ---
10
62
 
11
63
  # Google Sheets
@@ -15,6 +15,35 @@ mcp_reads:
15
15
  notion-get-async-task,
16
16
  notion-query-data-sources
17
17
  ]
18
+ metadata:
19
+ {
20
+ "openclaw": {
21
+ "setup": {
22
+ "routes": [
23
+ {
24
+ "kind": "oauth",
25
+ "label": "Notion",
26
+ "provider": "notion",
27
+ "credentialKey": "notion_mcp_access_token",
28
+ "description": "Pages, databases, and blocks",
29
+ "steps": [
30
+ "Click Connect and approve access in the browser — Workbench uses Notion's hosted MCP OAuth, so no app credentials are needed."
31
+ ],
32
+ "oauth": {
33
+ "stateKey": "notion_oauth",
34
+ "authUrl": "https://mcp.notion.com/authorize",
35
+ "tokenUrl": "https://mcp.notion.com/token",
36
+ "tokenAuth": "pkce-only",
37
+ "port": 18982,
38
+ "registrationEndpoint": "https://mcp.notion.com/register",
39
+ "sharedIosSession": true,
40
+ "scopes": []
41
+ }
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ }
18
47
  ---
19
48
 
20
49
  # Notion
@@ -8,15 +8,62 @@ credentials: [spotify_access_token]
8
8
  allow_list: [https://api.spotify.com/v1/]
9
9
  metadata:
10
10
  {
11
- "openclaw":
12
- {
13
- "requires":
11
+ "openclaw": {
12
+ "requires": {
13
+ "credentials": [
14
+ "spotify_access_token"
15
+ ],
16
+ "credentialChecks": {
17
+ "spotify_access_token": {
18
+ "url": "https://api.spotify.com/v1/me"
19
+ }
20
+ }
21
+ },
22
+ "setup": {
23
+ "routes": [
14
24
  {
15
- "credentials": ["spotify_access_token"],
16
- "credentialChecks":
17
- { "spotify_access_token": { "url": "https://api.spotify.com/v1/me" } }
25
+ "kind": "oauth",
26
+ "label": "Spotify",
27
+ "provider": "spotify",
28
+ "credentialKey": "spotify_access_token",
29
+ "description": "Search, library, and playback control — playback requires Spotify Premium",
30
+ "helpUrl": "https://developer.spotify.com/dashboard",
31
+ "steps": [
32
+ "Search and library browsing work with any Spotify account; controlling playback (play, pause, skip) requires Spotify Premium and an open Spotify app on a device.",
33
+ "Create your own app at https://developer.spotify.com/dashboard (Spotify requires the app owner to hold a Premium subscription).",
34
+ "In the app settings, add these exact Redirect URIs: http://127.0.0.1:18974/callback (desktop) and, for mobile, the Redirect URI shown in this connect form (the scheme varies per build, e.g. qvac://oauth-callback or qvac-dev://oauth-callback).",
35
+ "Paste the Client ID above and click Connect, then approve access in the browser. No Client Secret is needed — Workbench uses PKCE."
36
+ ],
37
+ "fields": [
38
+ {
39
+ "key": "clientId",
40
+ "label": "Client ID",
41
+ "placeholder": "From your app at developer.spotify.com"
42
+ }
43
+ ],
44
+ "oauth": {
45
+ "stateKey": "spotify_oauth",
46
+ "authUrl": "https://accounts.spotify.com/authorize",
47
+ "tokenUrl": "https://accounts.spotify.com/api/token",
48
+ "tokenAuth": "pkce-only",
49
+ "port": 18974,
50
+ "sharedIosSession": true,
51
+ "scopes": [
52
+ "user-read-private",
53
+ "user-read-playback-state",
54
+ "user-modify-playback-state",
55
+ "user-read-currently-playing",
56
+ "playlist-read-private",
57
+ "playlist-read-collaborative",
58
+ "user-library-read",
59
+ "user-top-read",
60
+ "user-read-recently-played"
61
+ ]
62
+ }
18
63
  }
64
+ ]
19
65
  }
66
+ }
20
67
  }
21
68
  ---
22
69