@superglue/cli 0.1.0
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/dist/cli.js +23409 -0
- package/dist/skills/superglue/SKILL.md +674 -0
- package/dist/skills/superglue/references/databases.md +88 -0
- package/dist/skills/superglue/references/file-servers.md +136 -0
- package/dist/skills/superglue/references/integration.md +273 -0
- package/dist/skills/superglue/references/transforms-and-output.md +92 -0
- package/package.json +31 -0
- package/skills/superglue/SKILL.md +674 -0
- package/skills/superglue/references/databases.md +88 -0
- package/skills/superglue/references/file-servers.md +136 -0
- package/skills/superglue/references/integration.md +273 -0
- package/skills/superglue/references/transforms-and-output.md +92 -0
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: superglue
|
|
3
|
+
description: Build, test, deploy, and integrate superglue API tools via the sg CLI. Use when working with superglue tools, systems, APIs, the sg command, or integrating tools into codebases (SDK, REST API, webhooks). Covers tool configuration, credential management, OAuth, pagination, multi-step workflows, and production deployment.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# superglue CLI (`sg`) — Agent Reference
|
|
7
|
+
|
|
8
|
+
## CRITICAL RULES — READ FIRST
|
|
9
|
+
|
|
10
|
+
**Authentication & Credentials:**
|
|
11
|
+
|
|
12
|
+
- **Auth headers MUST be set explicitly** — credentials are NEVER auto-injected into requests
|
|
13
|
+
- Every request step (in tools AND `sg system call`) must include the appropriate auth header using `<<systemId_credentialKey>>` syntax
|
|
14
|
+
- OAuth systems also require explicit headers — only token refresh is automatic
|
|
15
|
+
|
|
16
|
+
**Pre-Building Testing:**
|
|
17
|
+
|
|
18
|
+
- **ALWAYS use `sg system call` to test endpoints BEFORE building tools**
|
|
19
|
+
- Verify authentication works, understand response structure, confirm field names
|
|
20
|
+
- Never guess API responses — test them first
|
|
21
|
+
- This prevents 90% of tool failures
|
|
22
|
+
|
|
23
|
+
**Example - `sg system call` with auth:**
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
sg system call --system-id notion --url "https://api.notion.com/v1/search" \
|
|
27
|
+
--method POST \
|
|
28
|
+
--headers '{"Authorization":"Bearer <<notion_access_token>>","Notion-Version":"2022-06-28"}' \
|
|
29
|
+
--body '{"filter":{"property":"object","value":"page"}}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Example - Tool step with auth:**
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"headers": {
|
|
37
|
+
"Authorization": "Bearer <<systemId_access_token>>"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Other Critical Rules:**
|
|
43
|
+
|
|
44
|
+
- `systemId` goes on each step's `config`, NOT at the tool level
|
|
45
|
+
- Steps execute sequentially; each step can reference previous step results
|
|
46
|
+
- `id` fields must be kebab-case for tools, snake_case for systems
|
|
47
|
+
- Simple `<<varName>>` only works for **top-level keys** (no dots, no nesting)
|
|
48
|
+
- For nested access use arrow functions: `<<(sourceData) => sourceData.currentItem.id>>`
|
|
49
|
+
- ALWAYS access step results via `.data`: `sourceData.stepId.data` not `.results`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g @superglue/cli
|
|
57
|
+
sg init # guided setup
|
|
58
|
+
sg system list # verify connection
|
|
59
|
+
sg tool build --config '{"id":"...","instruction":"...","steps":[...]}'
|
|
60
|
+
sg tool run --draft <draftId>
|
|
61
|
+
sg tool save --draft <draftId>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Config:** `SUPERGLUE_API_KEY` + `SUPERGLUE_API_ENDPOINT` env vars, or `.superglue/config.json` (created by `sg init`).
|
|
65
|
+
**Priority:** CLI flags > env vars > config file.
|
|
66
|
+
|
|
67
|
+
## Global Flags
|
|
68
|
+
|
|
69
|
+
| Flag | Description |
|
|
70
|
+
| ------------------ | ------------------------------------------- |
|
|
71
|
+
| `--json` | Force JSON output (auto-enabled in non-TTY) |
|
|
72
|
+
| `-y, --yes` | Auto-accept all confirmations |
|
|
73
|
+
| `--api-key <key>` | Override API key |
|
|
74
|
+
| `--endpoint <url>` | Override API endpoint |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Command Reference
|
|
79
|
+
|
|
80
|
+
### `sg init`
|
|
81
|
+
|
|
82
|
+
Interactive setup — API key, endpoint, output mode, policies. Creates `.superglue/`.
|
|
83
|
+
|
|
84
|
+
### Tool Commands
|
|
85
|
+
|
|
86
|
+
**`sg tool build`** — Register a tool config. Returns a `draftId`. Not AI-powered — you provide the full config.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
sg tool build --config tool.json # from file
|
|
90
|
+
sg tool build --config '{"id":"...","steps":[...]}' # inline JSON
|
|
91
|
+
sg tool build --id my-tool --instruction "..." --steps steps.json --payload '{"key":"val"}'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| `--config <file-or-json>` | Full JSON config (file path or inline JSON string) |
|
|
95
|
+
| `--id <id>` | Tool ID (kebab-case) |
|
|
96
|
+
| `--instruction <text>` | Human-readable description |
|
|
97
|
+
| `--steps <file>` | JSON file with steps array |
|
|
98
|
+
| `--payload <json>` | Sample payload (generates inputSchema) |
|
|
99
|
+
| `--file <key=path>` | Attach file reference (repeatable) |
|
|
100
|
+
|
|
101
|
+
**`sg tool run`** — Execute a draft or saved tool.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
sg tool run --draft <draftId> --payload '{"userId":"123"}'
|
|
105
|
+
sg tool run --tool my-tool --payload-file payload.json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| `--draft <id>` / `--tool <id>` | Draft ID or saved tool ID |
|
|
109
|
+
| `--payload <json>` / `--payload-file <path>` | Payload |
|
|
110
|
+
| `--include-step-results` | Include raw step results |
|
|
111
|
+
| `--include-config` | Include full tool config |
|
|
112
|
+
|
|
113
|
+
**`sg tool edit`** — Apply JSON Patch (RFC 6902) operations.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
sg tool edit --draft <draftId> --patches '[{"op":"replace","path":"/steps/0/config/url","value":"..."}]'
|
|
117
|
+
sg tool edit --tool my-tool --patches patches.json --test --payload '{...}'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| `--patches <json-or-file>` | JSON Patch array (inline or file) |
|
|
121
|
+
| `--test` | Run patched tool after accepting |
|
|
122
|
+
|
|
123
|
+
**`sg tool save`** — Persist draft to database. Deletes draft file on success.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
sg tool save --draft <draftId>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**`sg tool list` / `sg tool find`**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
sg tool list # all non-archived tools
|
|
133
|
+
sg tool find "shopify orders" # search (compact results)
|
|
134
|
+
sg tool find --id my-tool # exact ID lookup (full config)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### System Commands
|
|
138
|
+
|
|
139
|
+
**`sg system create`**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
sg system create --id slack --template slack --sensitive-credentials client_secret
|
|
143
|
+
sg system create --id my_api --url https://api.example.com --credentials '{"api_key":"..."}' --sensitive-credentials api_key
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| `--id <id>` | System ID (lowercase, underscores only) |
|
|
147
|
+
| `--url <url>` | API base URL |
|
|
148
|
+
| `--template <id>` | Template ID (stripe, shopify, slack, etc.) |
|
|
149
|
+
| `--credentials <json>` | Non-sensitive credentials |
|
|
150
|
+
| `--sensitive-credentials <fields>` | Comma-separated fields to prompt for securely |
|
|
151
|
+
| `--docs-url <url>` | Documentation URL to scrape |
|
|
152
|
+
|
|
153
|
+
**`sg system edit`** — Update system config or credentials.
|
|
154
|
+
**`sg system list` / `sg system find`** — List or search systems.
|
|
155
|
+
|
|
156
|
+
**`sg system call`** — **CRITICAL for tool building.** Make authenticated calls to APIs, databases, and file servers. Use this to:
|
|
157
|
+
|
|
158
|
+
- Test system authentication works
|
|
159
|
+
- Explore API endpoints and response structures
|
|
160
|
+
- Verify field names and data shapes BEFORE building tools
|
|
161
|
+
- Debug failing tools by testing individual endpoints
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Include auth header with credential placeholder
|
|
165
|
+
sg system call --url https://api.example.com/users \
|
|
166
|
+
--system-id my_api \
|
|
167
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}'
|
|
168
|
+
|
|
169
|
+
# POST request with auth and body
|
|
170
|
+
sg system call --url https://api.example.com/users \
|
|
171
|
+
--system-id my_api \
|
|
172
|
+
--method POST \
|
|
173
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}' \
|
|
174
|
+
--body '{"name":"test"}'
|
|
175
|
+
|
|
176
|
+
# Database query (Postgres)
|
|
177
|
+
sg system call --url "postgres://<<my_db_host>>:5432/mydb" \
|
|
178
|
+
--system-id my_db \
|
|
179
|
+
--body '{"query":"SELECT * FROM users LIMIT 5"}'
|
|
180
|
+
|
|
181
|
+
# File server (SFTP)
|
|
182
|
+
sg system call --url "sftp://<<my_sftp_host>>:22/data" \
|
|
183
|
+
--system-id my_sftp \
|
|
184
|
+
--body '{"operation":"list","path":"/"}'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Flag | Description |
|
|
188
|
+
| ------------------- | --------------------------------------------------------- |
|
|
189
|
+
| `--url <url>` | Full URL with protocol (http/https/postgres/sftp/ftp/smb) |
|
|
190
|
+
| `--system-id <id>` | System ID for credential injection |
|
|
191
|
+
| `--method <method>` | HTTP method (GET, POST, PUT, DELETE, PATCH) |
|
|
192
|
+
| `--headers <json>` | HTTP headers JSON with credential placeholders |
|
|
193
|
+
| `--body <string>` | Request body (JSON string) |
|
|
194
|
+
| `--file <key=path>` | File references (repeatable) |
|
|
195
|
+
|
|
196
|
+
**`sg system docs`** — Search system documentation.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
sg system docs --system-id slack --keywords "send message channels"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**`sg system oauth`** — Authenticate via OAuth.
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
sg system oauth --system-id gmail --scopes "https://www.googleapis.com/auth/gmail.readonly"
|
|
206
|
+
sg system oauth --system-id my_api --grant-type client_credentials --scopes "read write"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| `--system-id <id>` | Required |
|
|
210
|
+
| `--scopes <scopes>` | Space-separated OAuth scopes (required) |
|
|
211
|
+
| `--grant-type <type>` | `authorization_code` (default) or `client_credentials` |
|
|
212
|
+
|
|
213
|
+
### Run Commands
|
|
214
|
+
|
|
215
|
+
**`sg run list`** — List execution runs. Filter by `--tool`, `--status`, `--source`, `--limit`.
|
|
216
|
+
**`sg run get <runId>`** — Get run details. `--fetch-results` to include data.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Tool Configuration — Full Schema
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"id": "kebab-case-tool-name",
|
|
225
|
+
"instruction": "Brief human-readable description of what this tool does",
|
|
226
|
+
"steps": [
|
|
227
|
+
{
|
|
228
|
+
"id": "unique-step-id",
|
|
229
|
+
"config": {
|
|
230
|
+
"systemId": "system-id",
|
|
231
|
+
"url": "https://api.example.com/endpoint?param=<<payload.field>>",
|
|
232
|
+
"method": "GET",
|
|
233
|
+
"headers": {
|
|
234
|
+
"Authorization": "Bearer <<system-id_access_token>>"
|
|
235
|
+
},
|
|
236
|
+
"queryParams": { "limit": "10" },
|
|
237
|
+
"body": "{ \"key\": \"<<payload.field>>\" }"
|
|
238
|
+
},
|
|
239
|
+
"dataSelector": "(sourceData) => sourceData.previousStep.data.items",
|
|
240
|
+
"transformCode": "(items) => items.map(i => ({ id: i.id, name: i.name }))",
|
|
241
|
+
"failureBehavior": "abort"
|
|
242
|
+
}
|
|
243
|
+
],
|
|
244
|
+
"outputTransform": "(sourceData) => sourceData.stepId.data",
|
|
245
|
+
"outputSchema": { "type": "object", "properties": {} },
|
|
246
|
+
"inputSchema": { "type": "object", "properties": {} }
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Step Config Fields
|
|
251
|
+
|
|
252
|
+
| Field | Type | Description |
|
|
253
|
+
| ------------- | ------ | -------------------------------------------- |
|
|
254
|
+
| `systemId` | string | System whose credentials to use |
|
|
255
|
+
| `url` | string | Full URL with `<<variable>>` placeholders |
|
|
256
|
+
| `method` | string | HTTP method |
|
|
257
|
+
| `headers` | object | HTTP headers with credential placeholders |
|
|
258
|
+
| `queryParams` | object | URL query parameters |
|
|
259
|
+
| `body` | string | Request body (JSON string with placeholders) |
|
|
260
|
+
| `pagination` | object | Auto-pagination config (see below) |
|
|
261
|
+
|
|
262
|
+
### Step Behavior Fields
|
|
263
|
+
|
|
264
|
+
| Field | Type | Description |
|
|
265
|
+
| ----------------- | ------ | ------------------------------------------------ |
|
|
266
|
+
| `dataSelector` | string | JS function controlling step input and loop mode |
|
|
267
|
+
| `transformCode` | string | JS function to transform the step's response |
|
|
268
|
+
| `failureBehavior` | string | `abort` (default), `continue`, or `skip` |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Credential Placeholders
|
|
273
|
+
|
|
274
|
+
System credentials are namespaced as `<<systemId_credentialKey>>` and resolved server-side at execution time. **You MUST explicitly reference them in headers.**
|
|
275
|
+
|
|
276
|
+
### Auth Header Patterns
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{"Authorization": "Bearer <<stripe_api_key>>"}
|
|
280
|
+
{"Authorization": "Bearer <<gmail_access_token>>"}
|
|
281
|
+
{"X-API-Key": "<<my_api_api_key>>"}
|
|
282
|
+
{"Authorization": "Basic <<(sourceData) => Buffer.from(sourceData.my_api_username + ':' + sourceData.my_api_password).toString('base64')>>"}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Credential Lifecycle
|
|
286
|
+
|
|
287
|
+
- Non-sensitive creds (`client_id`, `auth_url`, etc.) are stored via `--credentials`
|
|
288
|
+
- Sensitive creds (`api_key`, `client_secret`) use `--sensitive-credentials` for secure input
|
|
289
|
+
- OAuth tokens (`access_token`, `refresh_token`) are auto-refreshed before each step execution
|
|
290
|
+
- Placeholders like `<<gmail_access_token>>` always resolve to the current (refreshed) token
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Variables and Data Flow
|
|
295
|
+
|
|
296
|
+
### Variable Syntax
|
|
297
|
+
|
|
298
|
+
All step config fields support `<<variable>>` placeholders:
|
|
299
|
+
|
|
300
|
+
| Syntax | Resolves to |
|
|
301
|
+
| -------------------------- | --------------------------- |
|
|
302
|
+
| `<<fieldName>>` | Payload field or credential |
|
|
303
|
+
| `<<systemId_credKey>>` | System credential |
|
|
304
|
+
| `<<stepId.data.field>>` | Previous step result |
|
|
305
|
+
| `<<(sourceData) => expr>>` | JavaScript expression |
|
|
306
|
+
|
|
307
|
+
**CRITICAL**: Simple `<<varName>>` only works for **top-level keys**. No dots, no nesting.
|
|
308
|
+
|
|
309
|
+
- VALID: `<<userId>>`, `<<currentItem>>`, `<<stripe_api_key>>`
|
|
310
|
+
- INVALID: `<<currentItem.id>>`, `<<sourceData.userId>>` — these FAIL at runtime
|
|
311
|
+
|
|
312
|
+
For nested access, use arrow functions: `<<(sourceData) => sourceData.currentItem.id>>`
|
|
313
|
+
|
|
314
|
+
### sourceData Object
|
|
315
|
+
|
|
316
|
+
`sourceData` is the cumulative state available to all JS expressions (data selectors, transforms, variable expressions):
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
sourceData = {
|
|
320
|
+
// Payload fields at ROOT level (NEVER use sourceData.payload.*)
|
|
321
|
+
userId: "123",
|
|
322
|
+
date: "2024-01-15",
|
|
323
|
+
|
|
324
|
+
// Previous step results, keyed by step ID
|
|
325
|
+
// Object-selector step:
|
|
326
|
+
getUsers: { currentItem: {}, data: { users: [...] }, success: true },
|
|
327
|
+
// Array-selector (loop) step:
|
|
328
|
+
fetchDetails: [
|
|
329
|
+
{ currentItem: "id1", data: { name: "Alice" }, success: true },
|
|
330
|
+
{ currentItem: "id2", data: { name: "Bob" }, success: true },
|
|
331
|
+
],
|
|
332
|
+
|
|
333
|
+
// Current loop item (only set inside a looping step's config)
|
|
334
|
+
currentItem: { id: 1 },
|
|
335
|
+
|
|
336
|
+
// Credentials (flattened, namespaced)
|
|
337
|
+
systemId_access_token: "...",
|
|
338
|
+
systemId_api_key: "..."
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Step Result Envelope
|
|
343
|
+
|
|
344
|
+
**Every** step result is wrapped in an envelope — you MUST account for this.
|
|
345
|
+
|
|
346
|
+
**Object selector (or no selector)** — step runs once:
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
sourceData.stepId = { currentItem: <selectorOutput>, data: <apiResponse>, success: true }
|
|
350
|
+
// Access the API response:
|
|
351
|
+
sourceData.stepId.data
|
|
352
|
+
sourceData.stepId.data.users
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Array selector** — step loops, result is an array of envelopes:
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
sourceData.stepId = [
|
|
359
|
+
{ currentItem: <item1>, data: <response1>, success: true },
|
|
360
|
+
{ currentItem: <item2>, data: <response2>, success: true },
|
|
361
|
+
...
|
|
362
|
+
]
|
|
363
|
+
// Access all responses:
|
|
364
|
+
sourceData.stepId.map(item => item.data)
|
|
365
|
+
// Nested arrays:
|
|
366
|
+
sourceData.stepId.flatMap(item => item.data.results)
|
|
367
|
+
// Only successes:
|
|
368
|
+
sourceData.stepId.filter(item => item.success).map(i => i.data)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**NEVER** access step results without `.data` — `sourceData.stepId.results` hits the envelope, not the API response. Use `sourceData.stepId.data.results`.
|
|
372
|
+
|
|
373
|
+
### Data Selectors
|
|
374
|
+
|
|
375
|
+
Control what a step receives as input and whether it loops:
|
|
376
|
+
|
|
377
|
+
| Return type | Behavior |
|
|
378
|
+
| ------------------ | ----------------------------------- |
|
|
379
|
+
| Single object | Step runs once with that object |
|
|
380
|
+
| Array | Step runs once per item (loop mode) |
|
|
381
|
+
| `undefined`/`null` | Step receives full sourceData |
|
|
382
|
+
|
|
383
|
+
In loop mode, `sourceData.currentItem` is set to the current array element.
|
|
384
|
+
|
|
385
|
+
Empty arrays are valid — the step simply skips execution.
|
|
386
|
+
|
|
387
|
+
### Step Result References (in `<<>>` placeholders)
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
<<stepId.data>> — full response data (object-selector step)
|
|
391
|
+
<<stepId.data.field>> — nested field
|
|
392
|
+
<<stepId.data.items[0].id>> — array element
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Execution Pipeline
|
|
396
|
+
|
|
397
|
+
For each step in order:
|
|
398
|
+
|
|
399
|
+
1. Build `sourceData`: `{ ...originalPayload, ...previousStepResults, ...credentials }`
|
|
400
|
+
2. Run `dataSelector(sourceData)` → determines single vs loop execution
|
|
401
|
+
3. For each item: merge `currentItem` into `sourceData`, resolve `<<>>` variables, execute step
|
|
402
|
+
4. `transformCode` runs on the raw response → output becomes `.data` in the envelope
|
|
403
|
+
5. Wrap result: `{ currentItem, data, success }` and store in `sourceData[stepId]`
|
|
404
|
+
6. After all steps: run `outputTransform(sourceData)` to shape final output
|
|
405
|
+
|
|
406
|
+
### Complete Example: List-then-Detail Pattern
|
|
407
|
+
|
|
408
|
+
A tool that lists Gmail message IDs, then fetches details for each:
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"id": "get-recent-emails",
|
|
413
|
+
"instruction": "Fetches the 10 most recent Gmail emails with subject, sender, and snippet",
|
|
414
|
+
"steps": [
|
|
415
|
+
{
|
|
416
|
+
"id": "list-messages",
|
|
417
|
+
"config": {
|
|
418
|
+
"systemId": "gmail",
|
|
419
|
+
"url": "https://gmail.googleapis.com/gmail/v1/users/me/messages?maxResults=10",
|
|
420
|
+
"method": "GET",
|
|
421
|
+
"headers": { "Authorization": "Bearer <<gmail_access_token>>" }
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"id": "get-details",
|
|
426
|
+
"dataSelector": "(sourceData) => sourceData[\"list-messages\"].data.messages.map(m => m.id)",
|
|
427
|
+
"config": {
|
|
428
|
+
"systemId": "gmail",
|
|
429
|
+
"url": "https://gmail.googleapis.com/gmail/v1/users/me/messages/<<currentItem>>?format=metadata&metadataHeaders=Subject&metadataHeaders=From&metadataHeaders=Date",
|
|
430
|
+
"method": "GET",
|
|
431
|
+
"headers": { "Authorization": "Bearer <<gmail_access_token>>" }
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
],
|
|
435
|
+
"outputTransform": "(sourceData) => sourceData[\"get-details\"].map(item => { var h = item.data.payload.headers; var get = function(n) { var f = h.find(function(x) { return x.name === n; }); return f ? f.value : null; }; return { id: item.data.id, subject: get(\"Subject\"), from: get(\"From\"), date: get(\"Date\"), snippet: item.data.snippet }; })"
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
What happens at runtime:
|
|
440
|
+
|
|
441
|
+
1. **list-messages** runs once (no dataSelector) → `sourceData["list-messages"] = { currentItem: {}, data: { messages: [{id: "abc"}, {id: "def"}, ...] }, success: true }`
|
|
442
|
+
2. **get-details** dataSelector returns `["abc", "def", ...]` (an array) → step loops over each ID
|
|
443
|
+
3. Each loop iteration sets `currentItem` to the string ID, which `<<currentItem>>` injects into the URL
|
|
444
|
+
4. Loop results stored as: `sourceData["get-details"] = [{ currentItem: "abc", data: {id, snippet, payload...}, success }, ...]`
|
|
445
|
+
5. **outputTransform** maps over the array of envelopes, extracting `.data` fields from each
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## HTTP API Patterns
|
|
450
|
+
|
|
451
|
+
### Pagination
|
|
452
|
+
|
|
453
|
+
```json
|
|
454
|
+
{
|
|
455
|
+
"pagination": {
|
|
456
|
+
"type": "offset|cursor|page",
|
|
457
|
+
"pageSize": 100,
|
|
458
|
+
"cursorPath": "$.nextPageToken",
|
|
459
|
+
"stopCondition": "(response) => !response.hasMore"
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
| Type | How it works |
|
|
465
|
+
| -------- | ------------------------------------------------------------ |
|
|
466
|
+
| `offset` | Increments `offset` param by `pageSize` each page |
|
|
467
|
+
| `cursor` | Extracts next cursor from `cursorPath`, sends as query param |
|
|
468
|
+
| `page` | Increments `page` query param |
|
|
469
|
+
|
|
470
|
+
All types stop when `stopCondition` returns true, response is empty, or max pages reached.
|
|
471
|
+
|
|
472
|
+
### Common Auth Patterns by Service Type
|
|
473
|
+
|
|
474
|
+
| Service | Header |
|
|
475
|
+
| ---------------------------- | ----------------------------------------------------- |
|
|
476
|
+
| OAuth (Google, GitHub, etc.) | `"Authorization": "Bearer <<systemId_access_token>>"` |
|
|
477
|
+
| API Key (Stripe, etc.) | `"Authorization": "Bearer <<systemId_api_key>>"` |
|
|
478
|
+
| API Key in header | `"X-API-Key": "<<systemId_api_key>>"` |
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Systems
|
|
483
|
+
|
|
484
|
+
### Credential Model
|
|
485
|
+
|
|
486
|
+
- `credentials` — non-sensitive config stored directly (client_id, auth_url, scopes, etc.)
|
|
487
|
+
- `sensitiveCredentials` — secrets requiring secure UI input (api_key, client_secret)
|
|
488
|
+
- **NEVER ask users to paste secrets in chat** — always use `--sensitive-credentials`
|
|
489
|
+
|
|
490
|
+
### Templates
|
|
491
|
+
|
|
492
|
+
Templates auto-populate endpoints and OAuth config. Use `sg system find` to discover available templates.
|
|
493
|
+
|
|
494
|
+
**Preconfigured OAuth** (no user client_id/secret needed): slack, salesforce, asana, notion, airtable, jira, confluence
|
|
495
|
+
|
|
496
|
+
### OAuth Flow
|
|
497
|
+
|
|
498
|
+
1. `sg system create --id gmail --url https://gmail.googleapis.com --credentials '{"auth_url":"...","token_url":"..."}' --sensitive-credentials client_id,client_secret`
|
|
499
|
+
2. `sg system oauth --system-id gmail --scopes "..."`
|
|
500
|
+
3. User authenticates in browser → tokens saved automatically
|
|
501
|
+
|
|
502
|
+
### System IDs
|
|
503
|
+
|
|
504
|
+
- Lowercase letters, numbers, underscores only — **no hyphens**
|
|
505
|
+
- Used for credential namespacing: `<<systemId_credKey>>`
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Debugging Failed Tools
|
|
510
|
+
|
|
511
|
+
### Common Errors and Fixes
|
|
512
|
+
|
|
513
|
+
| Error | Cause | Fix |
|
|
514
|
+
| --------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
|
|
515
|
+
| 401 Unauthorized | Missing or invalid auth header | Add `"Authorization": "Bearer <<systemId_access_token>>"` to step headers |
|
|
516
|
+
| 403 Forbidden | Wrong scopes or permissions | Check OAuth scopes, re-authenticate |
|
|
517
|
+
| Empty `data: {}` | No outputTransform or dataSelector | Add `outputTransform` to extract from step results |
|
|
518
|
+
| Variable not resolved | Wrong placeholder syntax | Check `<<systemId_credKey>>` matches actual credential keys |
|
|
519
|
+
| Step references empty | Wrong step ID in reference | Verify `<<stepId.data.field>>` matches actual step IDs |
|
|
520
|
+
|
|
521
|
+
### Debug Workflow
|
|
522
|
+
|
|
523
|
+
1. Run with `--include-step-results` to see raw step responses
|
|
524
|
+
2. Check each step's `data` field — is the API returning what you expect?
|
|
525
|
+
3. Verify credential placeholders match `sg system find --id <systemId>` placeholder list
|
|
526
|
+
4. **Test API calls directly with `sg system call`** — isolate whether the issue is auth, endpoint, or transform:
|
|
527
|
+
```bash
|
|
528
|
+
# Test the exact URL from your failing step
|
|
529
|
+
sg system call --url "https://api.example.com/endpoint" \
|
|
530
|
+
--system-id my_api \
|
|
531
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}'
|
|
532
|
+
```
|
|
533
|
+
5. Compare `sg system call` response to what your tool expects — fix transforms accordingly
|
|
534
|
+
|
|
535
|
+
### Self-Healing Pattern
|
|
536
|
+
|
|
537
|
+
When an outputTransform or dataSelector fails, the executor retries with an LLM-generated fix. To help this:
|
|
538
|
+
|
|
539
|
+
- Throw descriptive errors: `throw new Error("Expected array at data.items, got: " + typeof data.items)`
|
|
540
|
+
- Check for null/undefined with `?.` and defaults
|
|
541
|
+
- Validate arrays with `Array.isArray()` before calling array methods
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Workflow Guide
|
|
546
|
+
|
|
547
|
+
### Pre-Building: Test with `sg system call`
|
|
548
|
+
|
|
549
|
+
**ALWAYS test endpoints with `sg system call` before building tools.** This is the most important step to avoid broken tools.
|
|
550
|
+
|
|
551
|
+
1. **Verify authentication** — Test that credentials work:
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
sg system call --url "https://api.example.com/me" \
|
|
555
|
+
--system-id my_api \
|
|
556
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}'
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
2. **Explore response structure** — Understand what the API returns:
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
sg system call --url "https://api.example.com/users?limit=2" \
|
|
563
|
+
--system-id my_api \
|
|
564
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}'
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
Look at the response to understand:
|
|
568
|
+
- Where is the data array? (`data.users`, `data.items`, `data.results`?)
|
|
569
|
+
- What fields are available? (exact field names matter!)
|
|
570
|
+
- Is there pagination info? (`nextCursor`, `hasMore`, `total`?)
|
|
571
|
+
|
|
572
|
+
3. **Test the exact endpoints your tool will use** — Don't guess:
|
|
573
|
+
```bash
|
|
574
|
+
# If your tool will fetch user details by ID:
|
|
575
|
+
sg system call --url "https://api.example.com/users/123" \
|
|
576
|
+
--system-id my_api \
|
|
577
|
+
--headers '{"Authorization":"Bearer <<my_api_access_token>>"}'
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Full Workflow
|
|
581
|
+
|
|
582
|
+
1. **Create system** → `sg system create --id my_api --url ... --sensitive-credentials api_key`
|
|
583
|
+
2. **Authenticate** → `sg system oauth` (if OAuth) or credentials are already set
|
|
584
|
+
3. **Test auth** → `sg system call` to verify credentials work
|
|
585
|
+
4. **Explore API** → `sg system docs` + more `sg system call` to test endpoints
|
|
586
|
+
5. **Build tool** → Construct full config JSON, `sg tool build --config '...'`
|
|
587
|
+
6. **Test** → `sg tool run --draft <id> --include-step-results`
|
|
588
|
+
7. **Iterate** → `sg tool edit --draft <id> --patches '[...]' --test`
|
|
589
|
+
8. **Save** → `sg tool save --draft <id>`
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Deploying Tools to Production
|
|
594
|
+
|
|
595
|
+
After building and saving a tool, integrate it into your application:
|
|
596
|
+
|
|
597
|
+
### REST API (Any Language)
|
|
598
|
+
|
|
599
|
+
```bash
|
|
600
|
+
# Run a tool
|
|
601
|
+
curl -X POST "https://api.superglue.cloud/v1/tools/{toolId}/run" \
|
|
602
|
+
-H "Authorization: Bearer $SUPERGLUE_API_KEY" \
|
|
603
|
+
-H "Content-Type: application/json" \
|
|
604
|
+
-d '{"inputs": {"userId": "123"}}'
|
|
605
|
+
|
|
606
|
+
# Webhook trigger (async, fire-and-forget)
|
|
607
|
+
curl -X POST "https://api.superglue.cloud/v1/hooks/{toolId}?token=$SUPERGLUE_API_KEY" \
|
|
608
|
+
-H "Content-Type: application/json" \
|
|
609
|
+
-d '{"userId": "123"}'
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### TypeScript SDK
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
import { configure, runTool } from "@superglue/client";
|
|
616
|
+
configure({ apiKey: process.env.SUPERGLUE_API_KEY });
|
|
617
|
+
const { data } = await runTool("my-tool-id", { inputs: { userId: "123" } });
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Python SDK
|
|
621
|
+
|
|
622
|
+
```python
|
|
623
|
+
from superglue_client import SuperglueClient
|
|
624
|
+
from superglue_client.api.tools import run_tool
|
|
625
|
+
client = SuperglueClient(base_url="https://api.superglue.cloud/v1", token=os.environ["SUPERGLUE_API_KEY"])
|
|
626
|
+
result = run_tool.sync(client=client, tool_id="my-tool-id", body={"inputs": {"userId": "123"}})
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**For complete integration patterns** (error handling, retries, webhooks, async execution), read `references/integration.md`.
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## Reference Files
|
|
634
|
+
|
|
635
|
+
For detailed documentation on specific topics, read these files in the `references/` directory:
|
|
636
|
+
|
|
637
|
+
| File | When to read |
|
|
638
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
639
|
+
| `references/integration.md` | **READ THIS** when deploying tools to production - SDK usage, REST API, webhooks, error handling |
|
|
640
|
+
| `references/databases.md` | Building tools that query PostgreSQL/MySQL databases |
|
|
641
|
+
| `references/file-servers.md` | Building tools that interact with FTP/SFTP/SMB file servers |
|
|
642
|
+
| `references/transforms-and-output.md` | Complex data transformations, output shaping, JS sandbox constraints |
|
|
643
|
+
|
|
644
|
+
**Important:** When the user asks about integrating superglue into their codebase, deploying tools, using the SDK, or calling tools from code, you MUST read `references/integration.md` for complete examples.
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## Draft Management
|
|
649
|
+
|
|
650
|
+
Drafts live in `.superglue/drafts/<draftId>.json`. Created by `build`, updated by `edit`, deleted by `save`. Ephemeral — not persisted across sessions.
|
|
651
|
+
|
|
652
|
+
## File References
|
|
653
|
+
|
|
654
|
+
Attach files with `--file key=path`. Reference in payloads with `file::<key>`. Auto-parsed via `/v1/extract`.
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
sg tool run --draft <id> --payload '{"data": "file::mysheet"}' --file mysheet=data.xlsx
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
## Configuration
|
|
661
|
+
|
|
662
|
+
`.superglue/config.json`:
|
|
663
|
+
|
|
664
|
+
```json
|
|
665
|
+
{
|
|
666
|
+
"apiKey": "...",
|
|
667
|
+
"endpoint": "https://api.superglue.cloud",
|
|
668
|
+
"output": { "mode": "stdout", "directory": ".superglue/output" },
|
|
669
|
+
"policies": { "callSystem": "ask_every_time", "editTool": "confirm" }
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
**callSystem:** `ask_every_time` | `run_gets_only` | `run_everything`
|
|
674
|
+
**editTool:** `confirm` | `auto_accept`
|