Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions .claude/skills/build-plugin/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: build-plugin
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.
metadata:
author: SquaredUp
version: "0.0.11"
version: "0.0.12"
---

# Building a SquaredUp Low-Code Plugin
Expand Down Expand Up @@ -44,15 +44,15 @@ Create a TaskCreate task for each phase. The flow deploys early and tests as it
- [ ] **Prerequisite** β€” `squaredup status`; ensure login + tenant (see [Prerequisites](#prerequisites))
- [ ] **Phase 1** β€” Explore the API
- [ ] **Phase 2** β€” Plan the plugin structure
- [ ] **Phase 3** β€” Scaffold files (icon, file structure, `docs/README.md`)
- [ ] **Phase 3** β€” Scaffold files (icon, file structure, `docs/README.md` draft) β†’ [readme.md](references/readme.md)
- [ ] **Phase 4** β€” Write `metadata.json`, `ui.json`, `configValidation.json` + its backing stream β€” the deployable **shell** β†’ [metadata.md](references/metadata.md), [ui.md](references/ui.md)
- [ ] **Checkpoint A** β€” Deploy the shell and authenticate (invoke `deploy-plugin`, probe auth) β†’ [checkpoints.md](references/checkpoints.md)
- [ ] **Phase 5** β€” Write import definitions and import streams; test each in parallel sub-agents. Repeat per dependency level if any step `dependsOn` another β†’ [index-defs.md](references/index-defs.md), [test-agent.md](references/test-agent.md)
- [ ] **Checkpoint B** β€” Redeploy, then trigger + await the import via the CLI so objects exist β†’ [checkpoints.md](references/checkpoints.md)
- [ ] **Phase 6** β€” Build + test data streams in parallel sub-agents β†’ [test-agent.md](references/test-agent.md), [data-streams.md](references/data-streams.md)
- [ ] **Phase 7** β€” Build OOB default content in a sub-agent (it reads [oob-content.md](references/oob-content.md))
- [ ] **Phase 8** β€” Write `custom_types.json` β†’ [common-patterns.md](references/common-patterns.md)
- [ ] **Phase 9** β€” Final validate and deploy β†’ invoke the `deploy-plugin` skill; re-index if import definitions changed since the last import
- [ ] **Phase 9** β€” Finalize `docs/README.md`, then final validate and deploy β†’ [readme.md](references/readme.md); invoke the `deploy-plugin` skill; re-index if import definitions changed since the last import

---

Expand Down Expand Up @@ -200,17 +200,7 @@ my-plugin/
dashboard1.dash.json
```

**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`).

The README must cover:

1. What the plugin monitors β€” objects imported, what dashboards show
2. Prerequisites / getting credentials β€” step-by-step, include required scopes/permissions
3. Configuration fields β€” table explaining every `ui.json` field: what it is, where to find the value, whether required
4. What gets indexed β€” list object types and what they represent
5. Known limitations β€” rate limits, permission requirements, API quirks

Write as if the user has never seen the API. They're reading it inside SquaredUp, not on the vendor's site.
**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`). **Draft it now per [readme.md](references/readme.md)**: overview, Setup, and Configuration fields in full; the remaining sections as placeholder headings. It is finalized in Phase 9, once testing has surfaced the real data streams and limitations.

**Other rules:**

Expand Down Expand Up @@ -324,8 +314,10 @@ Write `custom_types.json` β€” for this and other reusable patterns (built-in pro

---

## Phase 9: Final validate & deploy
## Phase 9: Finalize README, validate & deploy

**Finalize `docs/README.md` first** β€” complete the placeholder sections (What this plugin monitors, Data streams, What gets indexed, Known limitations) and run the completion checklist in [readme.md](references/readme.md). Source Known limitations from the reconciliation passes' API-level discoveries: every constraint that forced a fix in Phases 5–6 belongs there in user-facing words.

Invoke the `deploy-plugin` skill for the final validate, version bump, and deploy.
Then invoke the `deploy-plugin` skill for the final validate, version bump, and deploy.
Comment on lines +317 to +321

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”’ Security & Privacy | 🟠 Major | ⚑ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the referenced skill and related deployment instructions.
fd -a "SKILL.md" .claude/skills | sed -n '1,120p'
printf '\n---\n'
fd -a "readme.md" .claude/skills | sed -n '1,120p'
printf '\n---\n'

# Show the relevant section around the cited lines.
python3 - <<'PY'
from pathlib import Path
p = Path('.claude/skills/build-plugin/SKILL.md')
lines = p.read_text().splitlines()
for start,end in [(300,340)]:
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1}: {lines[i]}")
PY

Repository: squaredup/plugins

Length of output: 3015


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find deploy-plugin skill and inspect its user-confirmation / validation behavior.
fd -a "deploy-plugin" .claude/skills
printf '\n---\n'
rg -n "confirm|confirmation|checklist|validate|deploy|re-index|reindex|version bump|stop|fail" .claude/skills/build-plugin .claude/skills/deploy-plugin -S

Repository: squaredup/plugins

Length of output: 33966


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the deploy-plugin skill and any confirmation requirements.
fd -a "SKILL.md" .claude/skills/deploy-plugin
printf '\n---\n'
python3 - <<'PY'
from pathlib import Path
for path in [Path('.claude/skills/deploy-plugin/SKILL.md')]:
    if path.exists():
        lines = path.read_text().splitlines()
        print(f"FILE: {path}")
        for i,l in enumerate(lines,1):
            if any(k in l.lower() for k in ["confirm", "confirmation", "checklist", "validate", "deploy", "re-index", "reindex", "version bump", "stop", "fail"]):
                print(f"{i}: {l}")
PY

Repository: squaredup/plugins

Length of output: 2648


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.claude/skills/build-plugin/references/readme.md')
lines = p.read_text().splitlines()
for start,end in [(136,220)]:
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1}: {lines[i]}")
PY

Repository: squaredup/plugins

Length of output: 832


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.claude/skills/build-plugin/references/readme.md')
lines = p.read_text().splitlines()
for i,l in enumerate(lines,1):
    if 136 <= i <= 220:
        print(f"{i}: {l}")
PY

Repository: squaredup/plugins

Length of output: 832


Gate the final deploy and re-index on a passing checklist and explicit approval.
Phase 9 only says to run the README checklist before invoking deploy-plugin; it doesn’t require every item to pass, and deploy-plugin only validates before deploying. Make both steps hard gates before any tenant-affecting change.

🧰 Tools
πŸͺ› SkillSpector (2.3.11)

[warning] 269: [EA2] Autonomous Decision Making: Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Remediation: Add human-in-the-loop confirmation for destructive, irreversible, or high-impact operations. Never auto-execute commands that modify files, send data, or alter system state.

(Excessive Agency (EA2))


[warning] 32: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 32: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 42: [RA2] Session Persistence: Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Remediation: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent.

(Rogue Agent (RA2))

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/build-plugin/SKILL.md around lines 317 - 321, Update the
Phase 9 workflow to require the README completion checklist to pass in full and
obtain explicit approval before invoking deploy-plugin. Ensure deploy-plugin’s
validation also passes before deployment or re-indexing, and prevent any
tenant-affecting change when either the checklist, validation, or approval gate
fails.

Source: Linters/SAST tools


**Conditional final re-index.** If `indexDefinitions/*.json` or any import stream changed since the last successful import (the Checkpoint B run, or any re-index triggered by the [re-indexing rule](#re-indexing-rule--a-definition-change-leaves-imported-objects-stale)), the deployed tenant's objects are **stale** β€” they still match the **old** definition and won't pick up the new shape until the next scheduled import, up to `frequencyMinutes` away (default `720` = 12 hours). So after the final deploy lands, trigger + poll one more import (the [Checkpoint B](#checkpoint-b-redeploy--run-the-first-import) trigger/wait steps) so the deployed objects match the shipped definition. Skip only if no import definition or import stream has changed since the last import.
144 changes: 144 additions & 0 deletions .claude/skills/build-plugin/references/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# docs/README.md β€” the in-product documentation

`docs/README.md` is rendered **in-product** (as GitHub-flavored Markdown) when a user adds or configures the plugin, and the `documentation` link in `metadata.json` must point to it. The reader has never seen the vendor's API and is sitting on the config screen with empty fields in front of them β€” write every section for that person.

## Two-pass authoring

The README is written twice:

- **Phase 3 (draft)** β€” write the overview paragraph, **Setup**, and **Configuration fields** in full; the Phase 2 plan has everything they need. Create the remaining four sections as headings with a `<!-- finalized in Phase 9 -->` placeholder β€” their real content (which streams shipped, what testing revealed) doesn't exist yet, and guessing it now means shipping stale guesses later.
- **Phase 9 (finalize, before the final deploy)** β€” complete **What this plugin monitors**, **Data streams**, **What gets indexed**, and **Known limitations**, then run the [completion checklist](#completion-checklist-phase-9). Source **Known limitations** from the reconciliation passes' API-level discoveries: every constraint that forced a fix in Phases 5–6 β€” a restricted `timeframes`, a response-size cap, an import count cap, a rate limit, an auth quirk β€” belongs here in user-facing words. If it surprised a testing sub-agent, it will surprise a user.

## Structure

**No H1** β€” the product shows the plugin name above the rendered doc; open directly with the overview paragraph. All sections are required, in this order:

```markdown
<Overview: 1–3 sentences β€” what the plugin monitors, via which vendor API(s),
linking the product and the API docs.>

> ⚠️ <Optional: scope warning β€” editions/tiers/APIs the plugin does NOT
> cover. Omit the blockquote entirely if there's nothing to warn about.>
## Setup

<Numbered walkthrough from signing in to the vendor to pasting the credential
into the named config field. State required roles/scopes/permissions at the
step where the user grants them. Link every vendor page a step mentions.>

## Configuration fields

| Field | What it is | Where to find it | Required |
| ----- | ---------- | ---------------- | -------- |

<One row per ui.json field, bold field name matching its label exactly. After
the table: one sentence on what happens on save (the configValidation call)
and what a failure means.>

## What this plugin monitors

<Bullets grouping the data the way a user thinks about it, not the way the
API organizes it. Close with one line naming the out-of-the-box dashboards.>

## Data streams

<One bullet per stream: **displayName** β€” what it returns and its scope
(per-object or account-wide).>

## What gets indexed

| Object type | API source | Represents |
| ----------- | ---------- | ---------- |

<One row per objectType. Follow with a **Relationships:** line if objects
link to each other.>

## Known limitations

<Bullets: granularity/timeframe caps, rate limits, import count caps, data
freshness, permission constraints, and a read-only note if the plugin never
writes to the vendor.>
```

## Writing rules

- **Name the vendor's UI surfaces, not its endpoints** β€” "Console β†’ Settings β†’ API keys", not `GET /v1/keys`. Endpoints appear only in the **What gets indexed** API-source column.
- **Bold every field label and vendor UI element** the user must click or fill, matching its on-screen wording exactly.
- **Plain GFM only** β€” pipe tables, and blockquotes (`> ⚠️ …`) for admonitions. Never GitHub `[!NOTE]`/`[!WARNING]` alert syntax: the in-product renderer isn't GitHub and won't style it.
- **Link out** to the vendor's sign-in page, credential-creation page, and permission docs wherever Setup mentions them β€” the reader shouldn't need to search for any page a step names.

## Example

A finished README for the fictional battery-monitoring plugin from SKILL.md's Phase 2 example:

```markdown
Monitor your [Acme Energy](https://acme.example) installations and devices in
SquaredUp β€” battery health, telemetry history, alarms, and billing β€” via the
[Acme Cloud API](https://acme.example/docs/api).

> ⚠️ Requires an Acme **Business** subscription β€” Home accounts have no API
> access.
## Setup

You will need an Acme Cloud **API key**.

1. Sign in to the [Acme Cloud console](https://cloud.acme.example).
2. Go to **Settings β†’ API keys** and click **Create key**, giving it the
**Read-only** role β€” the plugin never writes.
3. Copy the key and paste it into the **API key** field.

## Configuration fields

| Field | What it is | Where to find it | Required |
| ----------- | ------------------------------------------------------- | --------------------------------------------- | -------- |
| **API key** | Authenticates every request via the `X-API-Key` header. | Acme Cloud console β†’ **Settings β†’ API keys**. | Yes |

On save, the plugin validates the key by fetching your account profile; an
invalid or expired key fails setup with an authentication error.

## What this plugin monitors

- **Battery health** β€” current charge, capacity, and cycle count per device.
- **Telemetry history** β€” hourly charge and temperature series per device.
- **Alarms and billing** β€” active alarms and daily billed cost per
installation.

The out-of-the-box dashboards include an estate-wide **Overview** plus a
perspective for each **Installation** and **Device**.

## Data streams

- **Battery Summary** β€” current battery state, one row per device.
- **Battery History** β€” hourly charge/temperature time series for a device.
- **Site Alarms** β€” active alarms for an installation.
- **Site Billing** β€” daily billed cost for an installation.

## What gets indexed

| Object type | API source | Represents |
| ---------------- | ----------------------- | -------------------------------------- |
| **Installation** | `GET /v2/installations` | A monitored site. |
| **Device** | `GET /v2/devices` | A physical device reporting telemetry. |

**Relationships:** each Device links to its parent Installation.

## Known limitations

- **Billing is daily-granularity** β€” billing timeframes start at last 7
days; shorter ranges aren't offered.
- **Rate limit** β€” the API allows 120 requests/minute; very large estates
may import slowly.
- **Read-only** β€” the plugin never creates, modifies, or deletes anything in
Acme Cloud.
```

## Completion checklist (Phase 9)

Verify each line against the plugin's actual files, not from memory:

- [ ] Every field in `ui.json` has a row in **Configuration fields**, bold name matching its label exactly.
- [ ] Every `objectType` in `metadata.json` has a row in **What gets indexed**.
- [ ] Every stream in `dataStreams/*.json` has a bullet in **Data streams**, named by its `displayName`.
- [ ] Every constraint that forced a Phase 5–6 fix (restricted `timeframes`, payload caps, import caps, rate limits) appears in **Known limitations** in user-facing words.
- [ ] No `<!-- finalized in Phase 9 -->` placeholders remain.
Comment on lines +143 to +144

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟑 Minor | ⚑ Quick win

Extend the checklist to cover all required limitation categories.

The template requires documenting authentication quirks, permission constraints, freshness, and read-only behavior, but this checklist only names timeframe, payload, import-count, and rate-limit constraints. A README can therefore pass the checklist while still omitting required user-facing limitations.

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/build-plugin/references/readme.md around lines 143 - 144,
Extend the README completion checklist entry for Known limitations to explicitly
require user-facing documentation of authentication quirks, permission
constraints, data freshness, and read-only behavior, alongside the existing
timeframe, payload, import-count, and rate-limit constraints.

Loading