Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@../../../../.config/AGENTS/skills/build-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@../../../../.config/AGENTS/skills/validate-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: build-plugin
description: build a Grafana plugin using the standard build process (frontend and backend if applicable)
---

@../../../../.config/AGENTS/skills/build-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: validate-plugin
description: validate a Grafana plugin using the official Grafana plugin validator
---

@../../../../.config/AGENTS/skills/validate-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Build Grafana Plugin

## Usage

```
/build-plugin
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mckn added separate skill for building the plugin.

  1. Figures out package manager using package.json
  2. Checks if it has a backend based on backend prop of package.json
  3. Build using instructions.md and run build and mage as fallbacks

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice! Looks great 🙌🏻

```

Run this from the root of your plugin directory.

## Steps

1. Detect the package manager. Check the `packageManager` field in `package.json` first, then fall back to lock file detection:
```bash
PKG_MANAGER=$(
if grep -q '"packageManager"' package.json 2>/dev/null; then
grep '"packageManager"' package.json | sed -E 's/.*"packageManager" *: *"([^@]+).*/\1/'
elif [ -f "pnpm-lock.yaml" ]; then
echo "pnpm"
elif [ -f "yarn.lock" ]; then
echo "yarn"
else
echo "npm"
fi
)
```

2. Check if the plugin has a backend:
```bash
HAS_BACKEND=$(grep -c '"backend" *: *true' src/plugin.json || true)
```

3. Build the frontend following the build instructions in `.config/AGENTS/instructions.md`. For detailed packaging steps refer to the packaging documentation linked there:
```bash
${PKG_MANAGER} run build
```
If the build fails, stop and report the error to the user.

4. If `HAS_BACKEND` is non-zero (backend plugin detected), build the backend following the build instructions and packaging documentation linked in `.config/AGENTS/instructions.md`:
- The backend must be built using `mage` with the build targets provided by the Grafana plugin Go SDK:
```bash
mage -v
```
- If `mage` is not installed, stop and tell the user: "mage is required to build the backend. Install it from https://magefile.org or run: go install github.com/magefile/mage@latest"
- If the build fails, stop and report the error to the user.
- After a successful backend build, ensure all backend binaries in `dist/` have execute permissions:
```bash
chmod 0755 dist/gpx_*
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Validate Grafana Plugin

## Important

Always use the bash commands below directly.

## Usage
Copy link
Contributor

Choose a reason for hiding this comment

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

these are instructions for the LLM. not the user. are you telling the LLM to use /validate-plugin or the user?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the LLM, I am trying to compare like which is the better way to validate the plugin - through MCP or SKILLS. If we have an MCP registered with validated plugin in the description, it uses the MCP. So the above instruction is to directly use the CLI command.


```
/validate-plugin
```

Run this from the root of your plugin directory.

## Steps

1. Check if `npx` or `docker` is available. npx is preferred, docker is the fallback:
Copy link
Contributor

Choose a reason for hiding this comment

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

docker is prefered for the validator, not npx

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, when I ran from the Codex CLI or Claude code CLI npx runs way faster.

Copy link
Contributor

Choose a reason for hiding this comment

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

that's because it is skipping the security checks (which are inside the docker image) that's why it runs faster. But that's actually a good point. the security checks are very important at submission not necessarily on a fast-dev environment

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use the same runner as the plugin is scaffolded with?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For running the validator? Wouldn't it be better to use npx or docker? Since it is standalone CLI tool not tied to the plugin's package manager? and if nodejs is installed which is a requirement for plugin development npx is present.

```bash
RUN_ENGINE=$(command -v npx >/dev/null 2>&1 && echo "npx" || (command -v docker >/dev/null 2>&1 && echo "docker" || echo "none"))
```
If `RUN_ENGINE` is `none`, stop immediately and tell the user: "Neither npx nor docker is installed. Please install Node.js (for npx) or Docker to run the plugin validator."

2. Extract the plugin ID from `src/plugin.json` (or `plugin.json`). Sanitize `PLUGIN_ID` to only allow characters valid in a Grafana plugin ID:
```bash
PLUGIN_ID=$(grep '"id"' < src/plugin.json | sed -E 's/.*"id" *: *"(.*)".*/\1/' | tr -cd 'a-zA-Z0-9._-')
```

3. Run the `build-plugin` skill to build the plugin (frontend and backend if applicable).

4. Build the plugin zip archive for validation with a timestamp:
```bash
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ZIP_NAME="${PLUGIN_ID}-${TIMESTAMP}.zip"
cp -r dist "${PLUGIN_ID}"
zip -qr "${ZIP_NAME}" "${PLUGIN_ID}"
rm -rf "${PLUGIN_ID}"
```

5. Run the validator with JSON output using `$RUN_ENGINE` from step 1 and `$ZIP_NAME` from step 4:
If `$RUN_ENGINE` is `npx`:
```bash
npx --cache .cache/npm -y @grafana/plugin-validator@latest -jsonOutput $ZIP_NAME
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the need to set the --cache path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

when running from codex it is using the ~/.cache for npx cache and permission denied error is returned, so we are setting it to use the plugins .cache folder.

```
If `$RUN_ENGINE` is `docker`:
```bash
docker run --pull=always \
-v "${PWD}/${ZIP_NAME}:/archive.zip:ro" \
grafana/plugin-validator-cli -jsonOutput /archive.zip
```

6. Read and interpret the JSON output. Summarize:
- Total errors, warnings, and passed checks
- List each error with its title and detail
- List each warning with its title and detail
- Provide actionable suggestions to fix each issue

7. Inform the user that a zip file was created (include the filename) and suggest they remove it manually when done. Do NOT run `rm` to delete the zip — this tool does not have permission to remove files.
Loading