@superglue/cli 1.1.18 → 1.1.20

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.
Files changed (30) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/cli.js +832 -23922
  3. package/dist/skills/superglue/SKILL.md +240 -27
  4. package/dist/skills/superglue/references/access-rules.md +137 -0
  5. package/dist/skills/superglue/references/data-handling.md +303 -0
  6. package/dist/skills/superglue/references/databases.md +7 -3
  7. package/dist/skills/superglue/references/file-handling.md +160 -0
  8. package/dist/skills/superglue/references/file-servers.md +13 -37
  9. package/dist/skills/superglue/references/http-apis.md +248 -0
  10. package/dist/skills/superglue/references/redis.md +4 -5
  11. package/package.json +2 -1
  12. package/skills/superglue/SKILL.md +240 -27
  13. package/skills/superglue/references/access-rules.md +137 -0
  14. package/skills/superglue/references/data-handling.md +303 -0
  15. package/skills/superglue/references/databases.md +7 -3
  16. package/skills/superglue/references/file-handling.md +160 -0
  17. package/skills/superglue/references/file-servers.md +13 -37
  18. package/skills/superglue/references/http-apis.md +248 -0
  19. package/skills/superglue/references/redis.md +4 -5
  20. package/dist/dist/cli.js +0 -24370
  21. package/dist/dist/skills/superglue/SKILL.md +0 -678
  22. package/dist/dist/skills/superglue/agents/openai.yaml +0 -7
  23. package/dist/dist/skills/superglue/assets/superglue.png +0 -0
  24. package/dist/dist/skills/superglue/references/databases.md +0 -249
  25. package/dist/dist/skills/superglue/references/file-servers.md +0 -136
  26. package/dist/dist/skills/superglue/references/integration.md +0 -279
  27. package/dist/dist/skills/superglue/references/redis.md +0 -190
  28. package/dist/dist/skills/superglue/references/transforms-and-output.md +0 -92
  29. package/dist/skills/superglue/references/transforms-and-output.md +0 -92
  30. package/skills/superglue/references/transforms-and-output.md +0 -92
@@ -0,0 +1,248 @@
1
+ # HTTP APIs
2
+
3
+ Covers REST APIs, GraphQL, webhooks, and any HTTP-based service.
4
+
5
+ ## Step Configuration
6
+
7
+ ```typescript
8
+ {
9
+ type: "request",
10
+ systemId: "my_api",
11
+ url: "<<my_api_url>>/v1/users", // RECOMMENDED: use system URL variable for base URL
12
+ method: "GET", // GET, POST, PUT, DELETE, PATCH
13
+ headers: { "Authorization": "Bearer <<my_api_access_token>>" }, // supports <<variables>> and JS expressions
14
+ queryParams: { "limit": "<<limit>>", "status": "active" }, // supports <<variables>> and JS expressions
15
+ body: '{"name": "<<(sourceData) => sourceData.currentItem.name>>"}', // supports <<variables>> and JS expressions
16
+ pagination: { ... } // optional
17
+ }
18
+ ```
19
+
20
+ ### URL Best Practices
21
+
22
+ **Prefer system URL variables over hardcoded URLs:**
23
+
24
+ ```typescript
25
+ // RECOMMENDED: Environment-agnostic (works with dev/prod switching)
26
+ { "url": "<<salesforce_url>>/services/data/v58.0/sobjects/Account" }
27
+
28
+ // ACCEPTABLE: When URL differs significantly from system base URL
29
+ { "url": "https://api.stripe.com/v1/customers" }
30
+
31
+ // AVOID: Hardcoding URLs that match the system's base URL
32
+ { "url": "https://mycompany.salesforce.com/services/data/v58.0/sobjects/Account" }
33
+ ```
34
+
35
+ Using `<<systemId_url>>` enables the same tool to work across different environments (dev/prod) without modification. The URL resolves dynamically based on execution mode.
36
+
37
+ ## Authentication Patterns
38
+
39
+ ```javascript
40
+ // Bearer token
41
+ { "Authorization": "Bearer <<systemId_access_token>>" }
42
+
43
+ // API key in header
44
+ { "X-API-Key": "<<systemId_api_key>>" }
45
+
46
+ // Basic Auth — auto-encoded to Base64, do NOT manually encode
47
+ { "Authorization": "Basic <<systemId_username>>:<<systemId_password>>" }
48
+
49
+ // Runtime credentials from payload
50
+ { "Authorization": "Bearer <<(sourceData) => sourceData.user_access_token>>" }
51
+ ```
52
+
53
+ Headers starting with `x-` are treated as custom headers.
54
+ Modern APIs expect auth in headers, NOT query parameters, unless docs explicitly say otherwise.
55
+
56
+ ## Request Behavior
57
+
58
+ - **GET, HEAD, DELETE, OPTIONS**: Body is always stripped
59
+ - **POST, PUT, PATCH**: Body with leading `{` is JSON-parsed; empty body becomes undefined
60
+ - Default headers: `Accept: */*`, Chrome-like `User-Agent`
61
+ - HTTPS: `rejectUnauthorized: false` (accepts self-signed certs)
62
+
63
+ ### Response Handling
64
+
65
+ All HTTP responses are read as raw bytes, then classified by `detectFileType` (byte-level detection). See the file-handling skill for the full detection logic and file type reference.
66
+
67
+ - **Binary types** (PDF, Excel, DOCX, ZIP, GZIP): treated as files. Parsed content also becomes `data`. Later steps can reference the file via `file::<stepId>.raw/base64/extracted`.
68
+ - **`application/octet-stream`**: always treated as a file, even if byte-level detection falls back to `RAW`.
69
+ - **Large responses over 25 MB**: treated as files as a safety fallback so the runtime does not try to parse a huge unknown blob as RAW text/JSON.
70
+ - **RAW + Content-Disposition attachment**: treated as a file.
71
+ - **Smaller structured/text responses** (JSON, XML, CSV, YAML, HTML, plain text under the size limit): parsed inline to `data` only.
72
+
73
+ This means an HTTP step downloading a PDF or large `.bin` file will expose `stepFileKeys` and populate `sourceData.__files__`, while an ordinary JSON API response will usually just populate `sourceData.stepId.data`.
74
+
75
+ ### Body Resolution Order
76
+
77
+ For HTTP request steps, the runtime processes the body in this order:
78
+
79
+ 1. `<<>>` template variables are resolved via `replaceVariables`
80
+ 2. The resulting body string is JSON-parsed when possible
81
+ 3. `file::...` references are resolved on the parsed body object
82
+ 4. The HTTP strategy decides how to send the final body:
83
+ - raw bytes for `file::<key>.raw` when the **entire body** is a file ref
84
+ - base64 string content for `file::<key>.base64` when the API expects base64 inside JSON/XML
85
+ - `multipart/form-data` when the `Content-Type` header requests it and the body resolves to an object
86
+ - plain string body for strings
87
+ - `JSON.stringify(...)` for ordinary objects
88
+
89
+ File references are resolved **only in the body**, not in headers, query params, or URLs.
90
+
91
+ **Avoiding double-encoding:** The runtime stringifies objects at both step 1 (expression → template) and step 4 (object → fetch body). When the body contains nested JSON (e.g. LLM APIs), have `<<>>` expressions return a string via `JSON.stringify(...)`, or use a preceding transform step.
92
+
93
+ ### File Uploads
94
+
95
+ #### Raw Body Uploads
96
+
97
+ If the endpoint expects the file as the entire HTTP body, use:
98
+
99
+ ```typescript
100
+ {
101
+ method: "PUT",
102
+ headers: { "Content-Type": "application/pdf" },
103
+ body: "file::document.raw"
104
+ }
105
+ ```
106
+
107
+ This sends the exact original file bytes as the request body.
108
+
109
+ #### Base64-In-JSON/XML Uploads
110
+
111
+ If the endpoint expects the file encoded as base64 inside a structured payload, use:
112
+
113
+ ```typescript
114
+ {
115
+ method: "POST",
116
+ headers: { "Content-Type": "application/json" },
117
+ body: '{"fileBase64":"file::document.base64"}'
118
+ }
119
+ ```
120
+
121
+ This resolves the file bytes to a base64 string before the final `JSON.stringify(...)`.
122
+
123
+ #### Automatic Multipart Uploads
124
+
125
+ If the endpoint expects `multipart/form-data`, set the header and make the body a JSON object of form fields:
126
+
127
+ ```typescript
128
+ {
129
+ method: "POST",
130
+ headers: { "Content-Type": "multipart/form-data" },
131
+ body: '{"file":"file::report.raw","description":"monthly export"}'
132
+ }
133
+ ```
134
+
135
+ The runtime will:
136
+
137
+ - build a real `FormData` request
138
+ - turn `file::...raw` values into file parts using the stored filename and content type
139
+ - turn scalar values into text parts
140
+ - JSON-stringify non-file objects/arrays into text parts
141
+ - remove the user-supplied `Content-Type` header and let `fetch` set the multipart boundary automatically
142
+
143
+ Restrictions:
144
+
145
+ - the multipart body must resolve to an object of top-level form fields
146
+ - nested file refs inside objects are not supported
147
+ - do **not** manually include a multipart boundary in the header
148
+ - use `.raw` for file parts, `.base64` for base64 text fields, and `.extracted` only for text fields that should contain parsed content
149
+
150
+ ## Error Detection
151
+
152
+ ### HTTP Status Errors
153
+
154
+ Non-2xx responses throw with: method, URL, response body preview (1000 chars), masked config, retry count.
155
+
156
+ ### Smart Error Detection in 2xx Responses
157
+
158
+ Even successful responses are scanned for error indicators:
159
+
160
+ - `response.code` or `response.status` is 400-599 → throws
161
+ - Keys matching `error`, `errors`, `error_message`, `failure_reason`, `failure`, `failed` (up to depth 2) with non-empty values → throws
162
+ - Error message includes: _"To prevent this from happening, enable 'Continue on failure' in the step's Advanced Settings."_
163
+
164
+ Bypass: `failureBehavior: "continue"` skips all error checking. Can be set in the tool playground.
165
+
166
+ ## Retry Logic
167
+
168
+ ### Connection/Server Errors
169
+
170
+ - Default 1 retry (3 if keep-alive disabled), capped at server max
171
+ - Only retries if response was fast (under quick-retry threshold)
172
+ - Configurable delay between retries
173
+
174
+ ### Rate Limiting (429)
175
+
176
+ - Respects `Retry-After` header (seconds or date)
177
+ - Without header: exponential backoff `10^n * 1000ms + jitter` (max 1hr per wait)
178
+ - Total wait capped at `MAX_RATE_LIMIT_WAIT_MS`
179
+ - Separate from general retry count
180
+
181
+ ## Pagination
182
+
183
+ Makes multiple requests in a loop, merging results. Only configure if you've verified the exact API pagination mechanism from docs.
184
+
185
+ ### Configuration
186
+
187
+ ```typescript
188
+ pagination: {
189
+ type: "offsetBased" | "pageBased" | "cursorBased",
190
+ pageSize: "50",
191
+ cursorPath: "meta.next_cursor", // cursorBased only — JSONPath to cursor
192
+ stopCondition: "(response, pageInfo) => !response.data.meta.next_cursor"
193
+ }
194
+ ```
195
+
196
+ ### Variables (auto-injected)
197
+
198
+ | Type | Variable | Starts at | Increments by |
199
+ | ----------- | ---------------------------- | --------- | ------------------------ |
200
+ | pageBased | `<<page>>` | 1 | 1 |
201
+ | offsetBased | `<<offset>>` | 0 | pageSize |
202
+ | cursorBased | `<<cursor>>` | null | extracted via cursorPath |
203
+ | all | `<<limit>>` / `<<pageSize>>` | pageSize | — |
204
+
205
+ **CRITICAL**: The matching pagination variable MUST appear in the request (URL, queryParams, headers, or body). Throws if missing.
206
+
207
+ ### Stop Conditions
208
+
209
+ JS expression evaluated in sandbox. Receives `(response, pageInfo)`:
210
+
211
+ - `response.data` = parsed API response body
212
+ - `response.headers` = response headers
213
+ - `pageInfo = { page, offset, cursor, totalFetched }`
214
+ - Return `true` to **STOP**
215
+
216
+ Examples:
217
+
218
+ ```javascript
219
+ "!response.data.meta.next_cursor"; // no next cursor
220
+ "response.data.items.length === 0"; // empty page
221
+ "response.data.hasMore === false"; // explicit flag
222
+ "pageInfo.totalFetched >= 1000"; // item cap
223
+ ```
224
+
225
+ ### Safety Checks (only when stopCondition is set)
226
+
227
+ 1. **Identical pages 1 & 2** (both with data): Throws — pagination params aren't being applied
228
+ 2. **Both pages empty + stop didn't trigger**: Throws — broken stop condition
229
+ 3. **Duplicate consecutive response (after page 2)**: Auto-stops
230
+
231
+ ### Without stopCondition (fallback)
232
+
233
+ - Array shorter than pageSize → stop
234
+ - Duplicate response hash (against any previously seen page) → stop
235
+ - Non-array response → stop after first request
236
+ - Max 500 requests (vs 1000 max with a stopCondition)
237
+
238
+ ### Cursor Extraction
239
+
240
+ `cursorPath` is a JSONPath expression (auto-prefixed with `$.` if needed). Extracted via `jsonpath-plus`. Null cursor → stop.
241
+
242
+ **Special characters in cursorPath:** For property names containing `@` (e.g. OData's `@odata.nextLink`), use the property name directly as the cursorPath: `cursorPath: "@odata.nextLink"`. The engine handles `@`-prefixed paths automatically.
243
+
244
+ ## Output
245
+
246
+ Paginated steps merge all pages into a **single** result object. The step result is always accessed via `sourceData.stepId.data` — it is NOT an array of per-page results. Do NOT call `.map()` on a paginated step result.
247
+
248
+ Returns single object if one result, array if multiple (unwrapped from single-element array).
@@ -7,7 +7,6 @@
7
7
  type: "request",
8
8
  systemId: "my_redis",
9
9
  url: "redis://<<my_redis_username>>:<<my_redis_password>>@<<my_redis_host>>:<<my_redis_port>>/<<my_redis_database>>",
10
- method: "POST", // ignored for Redis but required by schema
11
10
  body: '{"command": "GET", "args": ["<<keyName>>"]}'
12
11
  }
13
12
  ```
@@ -23,7 +22,7 @@ rediss://user:password@host:port/database (TLS)
23
22
 
24
23
  - `redis://` for standard connections
25
24
  - `rediss://` for TLS-encrypted connections (e.g. Redis Cloud, AWS ElastiCache with encryption)
26
- - `/database` is the database number (0-15), defaults to 0 if omitted
25
+ - `/database` is the database number (defaults to 0 if omitted; max depends on the server's `databases` config, commonly 16)
27
26
 
28
27
  All credential variables are resolved before connecting. Trailing slashes are cleaned.
29
28
 
@@ -120,7 +119,7 @@ Multiple commands:
120
119
  ## Connection Management
121
120
 
122
121
  - A fresh connection is created per execution and closed after completion
123
- - TLS auto-configured for `rediss://` URLs (with `rejectUnauthorized: false`)
122
+ - TLS auto-configured for `rediss://` URLs (currently uses `rejectUnauthorized: false`)
124
123
  - 5-second connection timeout, 30-second command timeout
125
124
  - Array commands (pipeline) run on a single connection for efficiency
126
125
 
@@ -133,7 +132,7 @@ Default retries from server config. On final failure, error includes command and
133
132
  Returns the raw Redis response:
134
133
 
135
134
  - `GET` / `HGET`: string or null
136
- - `HGETALL`: object with field-value pairs (flattened array from Redis, parsed by ioredis)
135
+ - `HGETALL`: flat array of alternating field-value pairs (e.g., `["name", "Alice", "email", "alice@example.com"]`)
137
136
  - `LRANGE` / `SMEMBERS` / `KEYS`: array of strings
138
137
  - `SET` / `DEL` / `EXPIRE`: "OK" or integer
139
138
  - `INCR` / `LLEN` / `SADD`: integer
@@ -186,5 +185,5 @@ Use a data selector returning an array to execute a command per item:
186
185
 
187
186
  - All args must be strings (Redis protocol is text-based) - numbers are auto-coerced
188
187
  - Use `SCAN` instead of `KEYS` in production for large keyspaces
189
- - `HGETALL` returns an empty object `{}` for non-existent keys
188
+ - `HGETALL` returns an empty array `[]` for non-existent keys
190
189
  - Use array body for multi-command pipelines instead of separate steps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superglue/cli",
3
- "version": "1.1.18",
3
+ "version": "1.1.20",
4
4
  "bin": {
5
5
  "sg": "./dist/cli.js"
6
6
  },
@@ -15,6 +15,7 @@
15
15
  "fast-json-patch": "3.1.1"
16
16
  },
17
17
  "devDependencies": {
18
+ "@superglue/shared": "file:./_shared",
18
19
  "@types/node": "25.5.0",
19
20
  "tsup": "8.5.1",
20
21
  "typescript": "5.8.3"
@@ -19,8 +19,9 @@ description: "Build, test, deploy and integrate superglue tools via the sg CLI a
19
19
 
20
20
  **Authentication & Credentials:**
21
21
 
22
- - **Auth headers MUST be set explicitly** — credentials are NEVER auto-injected into requests or tool steps
23
- - Every request step (in tools AND `sg system call`) must include the appropriate auth header using `<<systemId_credentialKey>>` syntax
22
+ - **Authentication must always be explicitly configured** — nothing is injected automatically in any protocol
23
+ - For HTTP: include auth headers using `<<systemId_credentialKey>>` syntax (e.g., `"Authorization": "Bearer <<systemId_access_token>>"`)
24
+ - For databases/Redis/file servers: embed credential placeholders in the connection URL (e.g., `postgres://<<sys_user>>:<<sys_pass>>@host/db`)
24
25
  - OAuth systems also require explicit headers — only token refresh is automatic
25
26
 
26
27
  **Saving Tools:**
@@ -31,7 +32,7 @@ description: "Build, test, deploy and integrate superglue tools via the sg CLI a
31
32
 
32
33
  **Credentials in Non-Interactive Environments (AI Agents, CI):**
33
34
 
34
- - **Pass ALL credentials (including secrets) directly via `--credentials` JSON** — do NOT use `--sensitive-credentials` (it requires an interactive TTY which agents don't have)
35
+ - **Pass ALL credentials (including secrets) directly via `--credentials` JSON**
35
36
  - Ask the user to provide secret values, then pass them in `--credentials '{"api_key":"sk-xxx"}'`
36
37
 
37
38
  ---
@@ -121,15 +122,67 @@ sg tool save --draft <draftId>
121
122
 
122
123
  | Flag | Description |
123
124
  | ------------------ | ------------------------------------------- |
124
- | `--json` | Force JSON output (auto-enabled in non-TTY) |
125
+ | `--table` | Human-readable table output (default: JSON) |
126
+ | `--full` | Disable truncation of large fields |
125
127
  | `--api-key <key>` | Override API key |
126
128
  | `--endpoint <url>` | Override API endpoint |
127
129
 
130
+ ## Capability Presets
131
+
132
+ The CLI supports three capability presets that control which commands are available. Set during `sg init` or via `SUPERGLUE_CLI_PRESET` env var. Stored in `config.json` as `"preset"`.
133
+
134
+ | Preset | Description |
135
+ | --------- | ------------------------------------------------------------------ |
136
+ | `runner` | Run saved tools by ID only. Read-only lookups. No building/editing |
137
+ | `builder` | Runner + build/edit/save tools, call systems. No system CRUD |
138
+ | `admin` | Full access (default) |
139
+
140
+ ### Preset-to-Command Matrix
141
+
142
+ ```
143
+ Command runner builder admin
144
+ ─────────────────────────────────────────────────
145
+ sg init x x x
146
+ sg update x x x
147
+ sg skill x x x
148
+ sg tool build - x x
149
+ sg tool run --tool x x x
150
+ sg tool run --config/etc - x x
151
+ sg tool edit - x x
152
+ sg tool save - x x
153
+ sg tool find / list x x x
154
+ sg system create - - x
155
+ sg system edit - - x
156
+ sg system oauth - - x
157
+ sg system call - x x
158
+ sg system search-docs - x x
159
+ sg system find / list x x x
160
+ sg run list x x x
161
+ sg run get x x x
162
+ ```
163
+
164
+ ### Setting the Preset
165
+
166
+ ```bash
167
+ # During init (interactive or non-interactive)
168
+ sg init --preset runner --api-key "..." --global
169
+
170
+ # Via environment variable (overrides config.json)
171
+ export SUPERGLUE_CLI_PRESET=builder
172
+
173
+ # Manually edit .superglue/config.json
174
+ { "preset": "runner", "apiKey": "...", ... }
175
+ ```
176
+
177
+ Blocked commands print a clear error with the current preset name and how to change it.
178
+
128
179
  ## Command Reference
129
180
 
130
181
  ### `sg init`
131
182
 
132
- Interactive setup — API key, endpoint, output mode. Creates `.superglue/`.
183
+ Interactive setup — API key, endpoint, output mode, capability preset. Creates `.superglue/`.
184
+
185
+ Non-interactive: `sg init --api-key "..." --preset runner --global`
133
186
 
134
187
  ### Tool Commands
135
188
 
@@ -212,17 +265,16 @@ sg system create --name "Slack" --template slack
212
265
 
213
266
  **Full flag reference:**
214
267
 
215
- | Flag | Description |
216
- | ---------------------------------- | ---------------------------------------------------------------------------- |
217
- | `--name <name>` | Human-readable name — **REQUIRED** |
218
- | `--id <id>` | System ID (lowercase, underscores only) — derived from name if omitted |
219
- | `--url <url>` | API base URL — **REQUIRED** (auto-filled by `--template`) |
220
- | `--template <id>` | Template ID (stripe, shopify, slack, etc.) |
221
- | `--credentials <json>` | Credentials JSON (use for ALL creds in non-interactive mode) |
222
- | `--sensitive-credentials <fields>` | Comma-separated fields for masked input (TTY only — do NOT use in AI agents) |
223
- | `--docs-url <url>` | Documentation URL to scrape |
224
- | `--openapi-url <url>` | OpenAPI spec URL |
225
- | `--env <environment>` | Environment: `dev` or `prod` (default: prod) |
268
+ | Flag | Description |
269
+ | ---------------------- | ---------------------------------------------------------------------- |
270
+ | `--name <name>` | Human-readable name — **REQUIRED** |
271
+ | `--id <id>` | System ID (lowercase, underscores only) — derived from name if omitted |
272
+ | `--url <url>` | API base URL — **REQUIRED** (auto-filled by `--template`) |
273
+ | `--template <id>` | Template ID (stripe, shopify, slack, etc.) |
274
+ | `--credentials <json>` | Credentials JSON (all fields including secrets) |
275
+ | `--docs-url <url>` | Documentation URL to scrape |
276
+ | `--openapi-url <url>` | OpenAPI spec URL |
277
+ | `--env <environment>` | Environment: `dev` or `prod` (default: prod) |
226
278
 
227
279
  **`sg system edit`** — Update system config or credentials. Supports `--env dev|prod`.
228
280
  **`sg system list` / `sg system find`** — List or search systems. `find` supports `--env dev|prod`.
@@ -367,7 +419,7 @@ Basic auth is auto-encoded: if the value after `Basic ` isn't already base64, th
367
419
  ### Credential Lifecycle
368
420
 
369
421
  - Non-sensitive creds (`client_id`, `auth_url`, etc.) are stored via `--credentials`
370
- - Sensitive creds (`api_key`, `client_secret`) — in non-interactive mode (AI agents, CI), pass via `--credentials` JSON. In interactive TTY, use `--sensitive-credentials` for masked input, or set `SUPERGLUE_CRED_<FIELD>` env vars.
422
+ - Sensitive creds (`api_key`, `client_secret`) — pass via `--credentials` JSON: `--credentials '{"client_secret":"..."}'`
371
423
  - OAuth tokens (`access_token`, `refresh_token`) are auto-refreshed before each step execution
372
424
 
373
425
  ---
@@ -549,9 +601,8 @@ All types stop when `stopCondition` returns true, response is empty, or max page
549
601
  ### Credential Model
550
602
 
551
603
  - `credentials` — all credentials passed as JSON via `--credentials`
552
- - `sensitiveCredentials` — interactive masked prompt for secrets (TTY only, NOT for AI agents or CI)
553
- - **For AI agents / non-interactive use:** pass ALL credentials (including secrets like api_key, client_secret) directly via `--credentials '{"api_key":"..."}'`. Ask the user to provide the secret values, then include them in the JSON.
554
- - **For human interactive use:** use `--sensitive-credentials` for masked input of secrets
604
+ - **Pass ALL credentials** (including secrets like api_key, client_secret) directly via `--credentials '{"api_key":"..."}'`. Ask the user to provide the secret values, then include them in the JSON.
605
+ - OAuth tokens (`access_token`, `refresh_token`) are auto-refreshed before each step execution
555
606
 
556
607
  ### Templates
557
608
 
@@ -594,6 +645,165 @@ sg system oauth --system-id gmail --scopes "https://www.googleapis.com/auth/gmai
594
645
 
595
646
  ---
596
647
 
648
+ ## Tool Building Guide
649
+
650
+ ### Build Recipe
651
+
652
+ Before producing a tool config:
653
+
654
+ 1. Load relevant skills: data-handling and protocol skill(s) for the involved systems
655
+ 2. Use `sg system find` for every involved system — note `storedCredentials` and URL
656
+ 3. Use `sg system search-docs` for each system — look up endpoints, auth patterns, pagination, response structure
657
+ 4. Use `sg system call` to test 1-2 primary endpoints — verify response structure and field names before building
658
+ 5. Only then call `sg tool build --config '...'` with the full tool config
659
+
660
+ ### Planning Steps
661
+
662
+ - Fetch prerequisites: available projects, entity types, categories, etc.
663
+ - Each step = one API call, one DB query, one file operation, or a transform step (no compound ops)
664
+ - Final aggregation/filtering/sorting should happen in the `outputTransform`, not in a step
665
+ - Step instructions: 2-3 sentences describing the goal and expected data
666
+ - `instruction`: Write a 1-2 sentence summary of the tool's purpose. Never leave empty.
667
+
668
+ ### Step Result Envelopes
669
+
670
+ Every step result is wrapped — you MUST account for this in dataSelectors and outputTransform.
671
+
672
+ - **Object selector (or none)** — access via `sourceData.stepId.data`
673
+ - **Array selector** — access via `sourceData.stepId.map(i => i.data)`
674
+ - **Paginated step** — access via `sourceData.stepId.data` (pages are merged server-side into a single envelope — do NOT `.map()` over it)
675
+
676
+ NEVER access step results without `.data` — `sourceData.stepId.results` will fail because you're hitting the envelope, not the API response.
677
+
678
+ ### modify Flag
679
+
680
+ Set `modify: true` only when the step writes, updates, or deletes live data. Don't rely on HTTP method alone — a POST that only reads (e.g., GraphQL query) should be `modify: false`. Default is false.
681
+
682
+ ### Validation Rules
683
+
684
+ - Tool must have a valid `id` string
685
+ - Tool must have a `steps` array
686
+ - `systemId` is optional on request steps. Setting it makes that system's credentials available as `<<systemId_credKey>>` template variables, and enables `<<systemId_url>>` for the base URL. Omit for public APIs.
687
+ - Every request step must have a non-empty `url`
688
+ - Transform steps must have `transformCode`
689
+
690
+ ### Key Pitfalls
691
+
692
+ - NEVER guess API endpoints — always verify with `sg system search-docs` or `sg system call` first
693
+ - NEVER put `systemId` on the step object — it belongs inside `step.config.systemId`
694
+ - NEVER use `<<(sourceData) => sourceData.payload.X>>` — payload fields are at root level of sourceData
695
+ - NEVER use `<<currentItem.id>>` — use arrow function syntax: `<<(sourceData) => sourceData.currentItem.id>>`
696
+ - NEVER hardcode pagination params — use `<<page>>`, `<<offset>>`, `<<cursor>>`, `<<limit>>`
697
+ - NEVER add an `outputSchema` unless the user explicitly requested a specific response structure
698
+ - NEVER leave instructions empty
699
+ - ALWAYS explicitly configure authentication in every step — credentials are never automatically included in any protocol
700
+ - PREFER system URL variables (`<<systemId_url>>`) over hardcoded base URLs
701
+ - Check `sg system find` output for `storedCredentials` to know the exact variable names available
702
+ - `outputTransform` must be a single-line JS string (no literal newlines or tabs)
703
+ - NEVER use regex literals with `/` or complex escapes in transforms — they corrupt during serialization. Use `new URL()`, `.split()`, or `new RegExp()` instead. See data-handling reference "Serialization Safety".
704
+ - For complex request bodies, use a preceding transform step — don't put multi-statement logic inside `<<>>` expressions
705
+ - When the body contains nested/stringified JSON (e.g. LLM APIs): have `<<>>` expressions return a string via `JSON.stringify(...)`, and use a single expression for the whole body rather than mixing `<<>>` expressions with static JSON
706
+
707
+ ### Complex Body Construction
708
+
709
+ When a request body needs data from multiple steps or requires aggregation, use a preceding transform step:
710
+
711
+ ```javascript
712
+ // Step: prepareBody (transform)
713
+ transformCode: "(sourceData) => { var items = sourceData.step1.data.results; return { data: items.filter(function(i) { return i.active; }), count: items.length }; }";
714
+
715
+ // Step: submitData (request)
716
+ body: "<<(sourceData) => JSON.stringify(sourceData.prepareBody.data)>>";
717
+ ```
718
+
719
+ ---
720
+
721
+ ## Tool Editing Guide
722
+
723
+ Edit tools using RFC 6902 JSON Patch operations via `sg tool edit`.
724
+
725
+ ### Patch Format
726
+
727
+ Each operation:
728
+
729
+ ```typescript
730
+ {
731
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test",
732
+ path: string, // JSON Pointer (e.g., "/steps/0/config/url")
733
+ value?: any, // required for add, replace, test
734
+ from?: string // required for move, copy
735
+ }
736
+ ```
737
+
738
+ ### Key Paths
739
+
740
+ - `/instruction` — tool description
741
+ - `/steps/N` — step at index N
742
+ - `/steps/N/config/url`, `/steps/N/config/method`, `/steps/N/config/headers`, etc.
743
+ - `/steps/N/dataSelector` — JS function controlling input + loop mode
744
+ - `/outputTransform` — final output shaping function
745
+ - `/outputSchema` — optional JSON schema for output
746
+
747
+ ### Operations
748
+
749
+ - **`replace`** — Change an existing value. **Path must exist** — if the field is `null` or absent, `replace` fails. Use `add` instead for optional fields.
750
+ - **`add`** — Creates the field if missing, overwrites if it exists. **Prefer `add` over `replace`** when the field might be null or absent. Append to array with `/steps/-`.
751
+ - **`remove`** — Delete field or array element.
752
+ - **`move`** — Reorder or relocate.
753
+
754
+ ### Validation Rules
755
+
756
+ - Never patch `id` — tool IDs and draft IDs are immutable when editing
757
+ - `op` and `path` are required on every patch; `path` must start with `/`
758
+ - Patches are applied **sequentially** — later patches see effects of earlier ones
759
+ - After patches, same validation rules as building apply (valid id, steps array, URLs present)
760
+
761
+ ### Principles
762
+
763
+ - **Check result wrapping** — before writing any dataSelector or outputTransform patch, determine whether the upstream step used an object or array selector, and access `.data` accordingly
764
+ - **Don't forget downstream** — if you change a step's output shape, check if later dataSelectors and outputTransform need updating
765
+ - **Index shifts** — when removing array elements, subsequent indices shift down. Account for this in multi-patch operations.
766
+
767
+ ---
768
+
769
+ ## Systems Handling Guide
770
+
771
+ Systems are reusable building blocks that store configuration details and credentials.
772
+
773
+ ### Credential Use in Tool Configurations
774
+
775
+ For every `systemId` referenced in a tool, credentials are namespaced as `<<systemId_credentialKey>>` and must be explicitly placed in the step config. For HTTP: in headers. For databases/Redis/file servers: in the connection URL. Nothing is injected automatically.
776
+
777
+ ```
778
+ System id="stripe", storedCredentials: api_key → "sk_proj****"
779
+ → Available as: <<stripe_api_key>>
780
+ ```
781
+
782
+ OAuth tokens (`access_token`, `refresh_token`) are auto-refreshed before each step execution. Access tokens must also be explicitly referenced in step headers.
783
+
784
+ ### System URL Variables
785
+
786
+ System URLs are available as `<<systemId_url>>` and should be used instead of hardcoding base URLs:
787
+
788
+ ```
789
+ System id="salesforce", url="https://mycompany.salesforce.com"
790
+ → Available as: <<salesforce_url>>
791
+
792
+ Step config: { "url": "<<salesforce_url>>/services/data/v58.0/sobjects/Account" }
793
+ ```
794
+
795
+ ### Dev/Prod Environments
796
+
797
+ `environment` is `"dev"` or `"prod"` (or unset for legacy systems). Set at creation only — immutable afterward. Two systems with the same ID but different environments are automatically linked. Dev systems inherit documentation from their linked prod system. When creating a dev system, always ask for new credentials — never copy from prod.
798
+
799
+ Tools reference systems by ID only. Execution mode determines which environment is used (dev mode falls back to prod if no dev system exists).
800
+
801
+ ### System-Specific Instructions
802
+
803
+ Systems may include `specificInstructions` from the user (visible in `sg system find` output). Follow them when present. These capture API constraints, rate limits, special endpoints, auth requirements, or usage patterns.
804
+
805
+ ---
806
+
597
807
  ## Debugging Failed Tools
598
808
 
599
809
  ### Debug Workflow
@@ -653,13 +863,16 @@ with client as c:
653
863
 
654
864
  For detailed documentation on specific topics, read these files in the `references/` directory:
655
865
 
656
- | File | When to read |
657
- | ------------------------------------- | ------------------------------------------------------------------------------------------------ |
658
- | `references/integration.md` | **READ THIS** when deploying tools to production - SDK usage, REST API, webhooks, error handling |
659
- | `references/databases.md` | Building tools that query PostgreSQL or Microsoft SQL Server (Azure SQL) databases |
660
- | `references/redis.md` | Building tools that interact with Redis (commands, pipelines, data types) |
661
- | `references/file-servers.md` | Building tools that interact with FTP/SFTP/SMB file servers |
662
- | `references/transforms-and-output.md` | Complex data transformations, output shaping, JS sandbox constraints |
866
+ | File | When to read |
867
+ | ----------------------------- | ------------------------------------------------------------------------------------------------ |
868
+ | `references/integration.md` | **READ THIS** when deploying tools to production - SDK usage, REST API, webhooks, error handling |
869
+ | `references/databases.md` | Building tools that query PostgreSQL or Microsoft SQL Server (Azure SQL) databases |
870
+ | `references/redis.md` | Building tools that interact with Redis (commands, pipelines, data types) |
871
+ | `references/file-servers.md` | Building tools that interact with FTP/SFTP/SMB file servers |
872
+ | `references/data-handling.md` | Variables, selectors, result envelopes, transforms, JS sandbox constraints |
873
+ | `references/file-handling.md` | File detection, parsing, producedFiles, file references, aliasing rules |
874
+ | `references/http-apis.md` | HTTP step config — auth patterns, pagination, retries, error detection |
875
+ | `references/access-rules.md` | RBAC roles, tool/system permissions, custom rules, mutation detection (enterprise only) |
663
876
 
664
877
  **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.
665
878