Skip to content

Commit 9529291

Browse files
authored
Merge pull request #57 from squaredup/work/dc/skill
Experimental: AI Skill for building plugins
2 parents 4f07e0e + d8fd4d4 commit 9529291

10 files changed

Lines changed: 1894 additions & 0 deletions

File tree

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
name: build-plugin
3+
description: Guides building a SquaredUp low-code plugin for HTTP/REST APIs, from API exploration through deployment. Use when the user wants to integrate a service with SquaredUp, add a new data source, connect to a third-party tool, "pull data from", or "monitor" any service in SquaredUp.
4+
metadata:
5+
author: SquaredUp
6+
version: "0.0.3"
7+
---
8+
9+
# Building a SquaredUp Low-Code Plugin
10+
11+
> **Scope:** Web API-based plugins only. If the target tool has no usable REST API, PowerShell may be a better fit — suggest it and stop.
12+
13+
**Announce at start:** "I'm using the build-plugin skill."
14+
15+
---
16+
17+
## Required user inputs
18+
19+
| Input | When to ask | Why |
20+
| ------------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
21+
| **Author handle** (GitHub handle or display name) | Before writing `metadata.json` (Phase 4) | Goes into `author.name`. Guessing from git config frequently picks the wrong identity. |
22+
23+
If the user has already volunteered the answer earlier in the conversation or you're updating a plugin, use that and skip the prompt. Otherwise, ask — even in autonomous mode.
24+
25+
---
26+
27+
## When to Use
28+
29+
- Building a new plugin for an HTTP/REST API
30+
- Adding data streams or dashboards to an existing plugin
31+
- Any request to integrate a service, "pull data from", or "monitor" a service in SquaredUp
32+
- Adding a new data source or integration to a SquaredUp workspace
33+
34+
---
35+
36+
## Checklist
37+
38+
Create a TaskCreate task for each phase:
39+
40+
- [ ] **Phase 1** — Explore the API
41+
- [ ] **Phase 2** — Plan the plugin structure
42+
- [ ] **Phase 3** — Scaffold files (icon, file structure, `docs/README.md`)
43+
- [ ] **Phase 4** — Write `metadata.json` and `ui.json` → read [metadata.md](references/metadata.md) and [ui.md](references/ui.md)
44+
- [ ] **Phase 5** — Write import definitions → read [index-defs.md](references/index-defs.md)
45+
- [ ] **Phase 6** — Write data streams → read [data-streams.md](references/data-streams.md)
46+
- [ ] **Phase 7** — Write OOB default content → read [oob-content.md](references/oob-content.md)
47+
- [ ] **Phase 8** — Write `custom_types.json` → read [common-patterns.md](references/common-patterns.md)
48+
- [ ] **Phase 9** — Validate and deploy → invoke the `deploy-plugin` skill
49+
50+
---
51+
52+
## Phase 1: Explore the API
53+
54+
Before writing a single file, understand the API. **Use `AskUserQuestion` to ask for API documentation URLs, OpenAPI/Swagger specs, Postman collections, or any other reference material.** You can also search online, but verify you're looking at docs for the exact product/version the user wants.
55+
56+
1. **Find the docs** — Gather URLs or spec files from the user, then fetch and read them.
57+
2. **Identify the object model** — What are the core entities? (e.g. installations, devices, sites). These become the **indexed objects** in SquaredUp — available for drilldown, search, scoping dashboards, and use as variables.
58+
3. **Find the list endpoints** — Used to import objects. Prefer fetching **50–250 records per page** across multiple requests — SquaredUp has a per-page timeout but supports as many paged requests as needed.
59+
4. **Find the data endpoints** — These power data streams. Identify whether each is scoped to a single object, multiple objects, or global (no object context).
60+
5. **Understand pagination** — Cursor/next-token, or offset/limit? Separate concern from response transformation.
61+
6. **Note the auth pattern** — API key in header, Bearer token, OAuth2, Basic auth? Determine from the docs.
62+
63+
---
64+
65+
## Phase 2: Plan the Plugin Structure
66+
67+
This phase produces a written plan and a user-approval gate before any files are written. Object types, import shape, and sourceId format are expensive to change once Phase 3+ commits them to JSON — Phase 2 is where scope errors are cheap to fix.
68+
69+
### The plan must cover
70+
71+
1. **Object types** — Every type that should appear in the SquaredUp graph. These go in `objectTypes` in `metadata.json` and as `sourceType` throughout.
72+
2. **Import steps** — Let the API shape dictate: one step returning many types, or separate steps per type.
73+
3. **Data streams** — For each object type, plan:
74+
- A **summary/current state** stream (`"timeframes": false`, returns current values)
75+
- A **history/metrics** stream (supports timeframes, returns time-series rows)
76+
- Any **cross-object** streams scoped to a parent (e.g. alarms for an installation)
77+
- **Prefer configurable streams** over hardcoded ones — use a UI parameter rather than multiple streams for the same endpoint with different values.
78+
4. **What's intentionally omitted** — API capabilities not being implemented, and why. Highest-value section for catching scope creep.
79+
5. **Authentication** — Auth mechanism and any UX concerns (token expiry, rate limits, hard-to-obtain credentials).
80+
6. **OOB dashboards** — A **top-level summary dashboard** plus **one perspective per object type** scoped via a dashboard variable.
81+
7. **sourceId format** — Use the raw API ID wherever possible.
82+
83+
### Plan format
84+
85+
Post the plan as markdown with one `###` heading per item above. Short example:
86+
87+
```markdown
88+
## Plan
89+
90+
### Object types
91+
- `My Installation` — sites being monitored
92+
- `My Device` — physical devices reporting telemetry
93+
94+
### Import steps
95+
- `installations` — one step, returns both types
96+
97+
### Data streams
98+
- `batterySummary` — per-device, current state
99+
- `batteryHistory` — per-device, time-series
100+
- `siteAlarms` — per-installation
101+
102+
### What's intentionally omitted
103+
- Webhook ingestion (no v1 use case)
104+
105+
### Authentication
106+
- API key in `X-API-Key` header
107+
108+
### OOB dashboards
109+
- Overview, Installation perspective, Device perspective
110+
111+
### sourceId format
112+
- Installation: raw API `id`
113+
- Device: composite `{installationId}-{deviceId}` (API has no global device ID)
114+
```
115+
116+
### Approval gate
117+
118+
**When to fire:** when `metadata.json` doesn't exist yet in the plugin folder, OR when the planned `objectTypes` differs from the current `metadata.json`. Otherwise skip — incremental work that doesn't introduce new entities doesn't need the gate.
119+
120+
**How:** post the plan, then call `AskUserQuestion` **in the same turn** with three options:
121+
122+
- `Approve as written` → proceed to Phase 3
123+
- `Trim scope — start with less` → user wants a smaller MVP; ask what to cut
124+
- `Adjust — different objects/streams/auth` → user wants changes; ask what specifically
125+
126+
If the user picks anything other than approve (including "Other"), revise the plan and re-fire the gate with the updated plan. Loop until approval — a revised plan can introduce new wrong assumptions, so the second pass is doing real work, not theatre. If the user explicitly waives further gating ("just proceed", "looks fine, go", "stop asking"), honor that for the rest of this conversation.
127+
128+
---
129+
130+
## Phase 3: Scaffold Files
131+
132+
**Icon:** Find the official brand/product logo (SVG or PNG). Never auto-generate a generic icon — ask the user to supply one if you can't find an official logo.
133+
134+
**Post-process SVG icons if needed.** SquaredUp shows icons on dark/white backgrounds. Fix if the SVG lacks a background or is not square:
135+
136+
1. Set `width="512" height="512" viewBox="0 0 512 512"`
137+
2. Insert `<rect width="512" height="512" fill="BRAND_COLOR"/>` as the first child
138+
3. Wrap paths in `<g transform="translate(X, Y) scale(S)">` for ~10% padding: `S = min(409.6/w, 409.6/h)`, `X = (512−w*S)/2`, `Y = (512−h*S)/2`
139+
140+
**File structure:**
141+
142+
```
143+
my-plugin/
144+
v1/
145+
metadata.json
146+
ui.json
147+
icon.svg
148+
custom_types.json
149+
configValidation.json # preferred: validates config on setup
150+
docs/
151+
README.md # REQUIRED: shown in-product when users add the plugin
152+
indexDefinitions/
153+
default.json
154+
dataStreams/
155+
myStream.json
156+
scripts/
157+
myScript.js
158+
defaultContent/
159+
manifest.json
160+
scopes.json
161+
overviewDashboard.dash.json
162+
deviceDashboard.dash.json # single perspective — no sub-folder needed
163+
Installations/ # sub-folder only for multiple dashboards of the same type
164+
manifest.json
165+
dashboard1.dash.json
166+
```
167+
168+
**docs/README.md (required)** — surfaced in-product when a user adds the plugin. Always create as part of scaffolding; the `documentation` link in `metadata.json` must point to it (e.g. `https://github.com/squaredup/plugins/blob/main/plugins/MyPlugin/v1/docs/README.md`).
169+
170+
The README must cover:
171+
172+
1. What the plugin monitors — objects imported, what dashboards show
173+
2. Prerequisites / getting credentials — step-by-step, include required scopes/permissions
174+
3. Configuration fields — table explaining every `ui.json` field: what it is, where to find the value, whether required
175+
4. What gets indexed — list object types and what they represent
176+
5. Known limitations — rate limits, permission requirements, API quirks
177+
178+
Write as if the user has never seen the API. They're reading it inside SquaredUp, not on the vendor's site.
179+
180+
**Other rules:**
181+
182+
- `scopes.json`: only include scopes used by OOB dashboards. Don't add speculatively.
183+
- `configValidation.json`: optional but strongly preferred — see [common-patterns.md](references/common-patterns.md).
184+
- **Single-dashboard rule:** Only create a sub-folder under `defaultContent/` when you have **multiple dashboards** for the same type.
185+
186+
---
187+
188+
## Phases 4–8: Writing Files
189+
190+
Read the corresponding reference file before writing each phase:
191+
192+
| Phase | Files | Reference |
193+
| -------------------------- | --------------------------------------------------- | ---------------------------------------------------------------- |
194+
| 4 — Plugin identity & auth | `metadata.json`, `ui.json`, `configValidation.json` | [metadata.md](references/metadata.md), [ui.md](references/ui.md) |
195+
| 5 — Import definitions | `indexDefinitions/default.json` | [index-defs.md](references/index-defs.md) |
196+
| 6 — Data streams | `dataStreams/*.json`, `scripts/*.js` | [data-streams.md](references/data-streams.md) |
197+
| 7 — OOB default content | `defaultContent/`, `scopes.json` | [oob-content.md](references/oob-content.md) |
198+
| 8 — Custom types | `custom_types.json` | [common-patterns.md](references/common-patterns.md) |
199+
200+
For reusable patterns (built-in properties stream, configValidation steps), read [common-patterns.md](references/common-patterns.md).
201+
202+
---
203+
204+
## Phase 9: Validate & Deploy
205+
206+
Invoke the `deploy-plugin` skill.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Common Patterns and Custom Types
2+
3+
> **Note:** `$schema` is not a valid property in any SquaredUp plugin JSON file.
4+
5+
## Contents
6+
7+
- [custom_types.json](#custom_typesjson)
8+
- [Built-in properties stream](#built-in-properties-stream)
9+
- [Config validation steps](#config-validation-steps)
10+
11+
---
12+
13+
## custom_types.json
14+
15+
Adds friendly display names and FontAwesome icons per object type. The `sourceType` value must exactly match the type used in `objectMapping.type` in `indexDefinitions/default.json`.
16+
17+
```json
18+
[
19+
{
20+
"name": "My Installation",
21+
"sourceType": "My Installation",
22+
"icon": "house",
23+
"singular": "Installation",
24+
"plural": "Installations"
25+
},
26+
{
27+
"name": "My Device",
28+
"sourceType": "My Device",
29+
"icon": "microchip",
30+
"singular": "Device",
31+
"plural": "Devices"
32+
}
33+
]
34+
```
35+
36+
Use **FontAwesome** icon names (`fontawesome.com/icons`), lowercase kebab-case. Common icons: `house`, `bolt`, `sun`, `battery-full`, `plug`, `thermometer`, `factory`, `gear`, `globe`, `wind`, `microchip`, `rotate`, `car`, `droplet`, `atom`, `gas-pump`, `wifi`, `camera`, `display`, `building`, `key`.
37+
38+
---
39+
40+
## Built-in properties stream
41+
42+
SquaredUp includes a built-in `datastream-properties` stream that automatically shows the indexed properties of any object. Use in OOB dashboards for a "Properties" or "Details" tile — no custom stream needed:
43+
44+
```json
45+
"dataStream": {
46+
"id": "datastream-properties"
47+
}
48+
```
49+
50+
---
51+
52+
## Config validation steps
53+
54+
`configValidation.json` is optional but strongly preferred. Use a **lightweight endpoint** (e.g. `/me`, `/user`). No extra flag needed in `metadata.json` — the presence of the file is sufficient.
55+
56+
```json
57+
{
58+
"steps": [
59+
{
60+
"displayName": "Authenticate",
61+
"dataStream": { "name": "currentUser" },
62+
"required": true,
63+
"error": "Could not authenticate. Check your API key has the required scopes.",
64+
"success": "Connected successfully."
65+
},
66+
{
67+
"displayName": "Check data access",
68+
"dataStream": { "name": "installations" },
69+
"required": false,
70+
"error": "Authenticated but no installations found.",
71+
"success": "Installations accessible."
72+
}
73+
]
74+
}
75+
```
76+
77+
`required: true` — a failing step blocks the user from completing setup. Write error messages that name what to check, not just that something failed.
78+
79+
Steps can override stream parameters for validation-specific queries:
80+
81+
```json
82+
{
83+
"displayName": "Check warehouse access",
84+
"dataStream": {
85+
"name": "sqlQuery",
86+
"config": { "query": "select 1", "errorOnEmptyResults": true }
87+
},
88+
"required": true,
89+
"error": "No warehouse access.",
90+
"success": "Warehouse accessible."
91+
}
92+
```
93+
94+
`errorOnEmptyResults: true` causes the step to fail if the stream returns no rows — useful when empty means access was denied.

0 commit comments

Comments
 (0)