From 636394e507ea183c5293e6d4d3ec10c2aebd5d54 Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 10 Jun 2026 09:41:13 +0200 Subject: [PATCH 1/2] feat: harden plugin and add open source readiness scaffolding Skills: - tighten allowed-tools (drop unscoped find/sed/curl/oc delete; use Glob) - treat a working kubeconfig as proof of an existing cluster so pre-provisioned customers are never routed to create-cluster - drop redundant user-invocable defaults, add argument-hint to update-image Plugin packaging: - add marketplace.json so the repo serves as its own marketplace - add displayName, fix README install instructions and typo Open source readiness: - CI workflow running 'claude plugin validate --strict' on PRs and main - Release Please config + workflow (bumps plugin.json version, changelog) - Dependabot for GitHub Actions - CONTRIBUTING.md, AGENTS.md, CHANGELOG.md Co-Authored-By: Claude Fable 5 --- .claude-plugin/marketplace.json | 15 +++++++++++ .claude-plugin/plugin.json | 1 + .github/dependabot.yml | 6 +++++ .github/workflows/release-please.yml | 18 +++++++++++++ .github/workflows/validate.yml | 19 +++++++++++++ .release-please-config.json | 16 +++++++++++ .release-please-manifest.json | 3 +++ AGENTS.md | 36 +++++++++++++++++++++++++ CHANGELOG.md | 6 +++++ CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++ README.md | 6 ++--- skills/create-cluster/SKILL.md | 12 ++++++++- skills/deploy-app/SKILL.md | 2 -- skills/expose-app/SKILL.md | 4 +-- skills/getting-started/SKILL.md | 5 ++-- skills/login/SKILL.md | 1 - skills/prepare-app/SKILL.md | 10 +++---- skills/status/SKILL.md | 6 ++--- skills/update-image/SKILL.md | 2 +- 19 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 .claude-plugin/marketplace.json create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/release-please.yml create mode 100644 .github/workflows/validate.yml create mode 100644 .release-please-config.json create mode 100644 .release-please-manifest.json create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..62bd169 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,15 @@ +{ + "name": "intility", + "description": "Claude Code plugins from Intility — tools for the Intility Developer Platform.", + "owner": { + "name": "Intility", + "email": "devinfra@intility.no" + }, + "plugins": [ + { + "name": "cust-devplatform-plugin", + "source": "./", + "description": "A friendly companion for getting an app running on the Intility Developer Platform. Helps you create a cluster, deploy a containerized app, expose it on a URL, and update it later — without needing prior Kubernetes experience." + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 34c8b86..846768a 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,5 +1,6 @@ { "name": "cust-devplatform-plugin", + "displayName": "Intility Developer Platform", "version": "0.1.0", "description": "A friendly companion for getting an app running on the Intility Developer Platform. Helps you create a cluster, deploy a containerized app, expose it on a URL, and update it later — without needing prior Kubernetes experience.", "author": { diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ca79ca5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..bc8cfaa --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,18 @@ +name: release-please + +on: + push: + branches: [main] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + config-file: .release-please-config.json + manifest-file: .release-please-manifest.json diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..3a54f0c --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,19 @@ +name: validate + +on: + pull_request: + push: + branches: [main] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install Claude Code + run: npm install -g @anthropic-ai/claude-code + - name: Validate plugin + run: claude plugin validate . --strict diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 0000000..d8faa06 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "simple", + "include-component-in-tag": false, + "packages": { + ".": { + "extra-files": [ + { + "type": "json", + "path": ".claude-plugin/plugin.json", + "jsonpath": "$.version" + } + ] + } + } +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..466df71 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.1.0" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..dc65c5f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# AGENTS.md + +Guidance for AI coding agents (and humans) working on this repository. + +## What this is + +A Claude Code plugin: eight markdown skills that guide a customer from zero to a running, exposed app on the Intility Developer Platform. There is no application code — the "source" is SKILL.md prompts, YAML/JSON manifests, and reference docs. + +## Layout + +``` +.claude-plugin/plugin.json plugin manifest (version is bumped by Release Please — don't edit by hand) +.claude-plugin/marketplace.json lets this repo serve as its own marketplace +skills//SKILL.md one skill per directory +skills//references/ templates and example conversations, loaded on demand +``` + +## Conventions + +- **Keep SKILL.md under 500 lines.** Move templates, long examples, and walkthroughs to `references/` and link them — they're loaded only when needed. +- **Frontmatter:** `description` is written in third person and includes concrete trigger phrases. `allowed-tools` is the minimum the skill needs — prefer scoped patterns (`Bash(oc delete httproute*)`) over broad ones (`Bash(oc delete*)`); never pre-approve `find`, unscoped `curl`, or `sed` (use Glob/Read/Edit tools instead). +- **Skills detect state, they don't assume it.** Every skill starts by querying (`oc whoami`, `indev cluster list`) rather than trusting conversation memory. Keep it that way. +- **Tone:** plain language for Kubernetes beginners. One command at a time. Introduce a term after showing what it does. +- **Safety rails stay:** `internal` gateway by default, two-step confirmation before `public`, `status` stays read-only, never create a second cluster without explicit double confirmation. + +## Before committing + +```bash +claude plugin validate . --strict +``` + +This is also enforced by CI on every PR. + +## Commits + +Conventional Commits (`fix:`, `feat:`, `docs:`, …) — Release Please derives versions from them. See [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4633bb4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## 0.1.0 + +First alpha. Eight skills covering the full journey: `getting-started`, `status`, +`create-cluster`, `login`, `prepare-app`, `deploy-app`, `expose-app`, `update-image`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..93a52fd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing + +Thanks for helping make the Developer Platform plugin better. It's an early alpha — feedback and small fixes are exactly what it needs. + +## Found a bug? Have a wish? + +Open an [issue](https://github.com/intility/cust-devplatform-plugin/issues). Include what you asked Claude to do, what it tried (the failing command is the best clue), and the cluster name if relevant. + +## Making changes + +1. The plugin is markdown and JSON — skills live in `skills//SKILL.md`, with longer material in `skills//references/`. +2. Validate before committing: + + ```bash + claude plugin validate . --strict + ``` + +3. To try your changes live, add your local checkout as a marketplace in Claude Code: + + ``` + /plugin marketplace add /path/to/cust-devplatform-plugin + /plugin install cust-devplatform-plugin@intility + ``` + +4. Open a PR against `main`. The `validate` check must pass before merging. + +## Commit messages + +Use [Conventional Commits](https://www.conventionalcommits.org/) — releases are automated with Release Please, which derives the next version from commit messages: + +- `fix: …` → patch release +- `feat: …` → minor release +- `feat!: …` or `BREAKING CHANGE:` → major release +- `docs:`, `chore:`, `ci:` → no release + +## Releases + +Release Please opens (and keeps updating) a release PR as changes land on `main`. Merging that PR bumps `version` in `.claude-plugin/plugin.json`, updates `CHANGELOG.md`, and tags a GitHub Release. + +**Why the version bump matters:** installed users only receive plugin updates when the `version` field changes — merging the release PR is what actually ships your change. Don't edit the version by hand. diff --git a/README.md b/README.md index bd6b50f..ab8a500 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,14 @@ **1. Install this plugin** ```bash -/plugin marketplace add intility +/plugin marketplace add intility/cust-devplatform-plugin /plugin install cust-devplatform-plugin@intility - ``` **2. Tell Claude what you want** ``` -help me ship my app on Intility Developer PLatform +help me ship my app on Intility Developer Platform ``` That's the whole thing. The plugin detects where you are in the journey and walks you through the rest. @@ -93,6 +92,7 @@ A few things that aren't obvious up front: - **Tokens expire.** Both `indev` and `oc` log out after a few hours. If something fails with "Unauthorized", just say *"log me back in"*. - **Different repo, different view.** Claude only sees the manifests in the directory you're working from. Switching repos means switching scope. - **`update-image` keeps the local file in sync** — but only if you run it from the repo that contains the manifests. Otherwise, the YAML on disk will drift from the cluster. +- **macOS / Linux only for now.** The skills assume a POSIX shell. On Windows, use WSL. ## Found a bug? Have a wish? diff --git a/skills/create-cluster/SKILL.md b/skills/create-cluster/SKILL.md index 73fed8a..ce457d6 100644 --- a/skills/create-cluster/SKILL.md +++ b/skills/create-cluster/SKILL.md @@ -1,7 +1,6 @@ --- name: create-cluster description: Creates a single cluster on the Intility Developer Platform for a customer. Use when the user asks to "create a cluster", "get me a cluster", "set up a cluster", or is being routed here by the getting-started skill. Creates ONE cluster with sensible defaults unless the user explicitly asks for more, since this plugin assumes a many-apps-on-one-cluster model. -user-invocable: true allowed-tools: - AskUserQuestion - Bash(indev account show) @@ -10,6 +9,7 @@ allowed-tools: - Bash(indev cluster status*) - Bash(indev cluster get*) - Bash(indev login) + - Bash(oc whoami*) - Bash(sleep *) --- @@ -27,6 +27,7 @@ The `indev` token has expired. Don't retry the failing command. Run `indev login ```bash indev cluster list +oc whoami --show-server 2>/dev/null ``` If there is already at least one cluster, **do not create another**. Show what's there and ask: @@ -38,6 +39,15 @@ Q: "You already have a cluster (). Use that one?" - "No, I really need another" → continue ``` +**Also check `oc whoami --show-server`** — clusters provisioned by platform admins or a colleague won't appear in this user's `indev cluster list`, but a working kubeconfig means a cluster exists. If `indev cluster list` is empty but `oc whoami --show-server` returns a server, ask: + +``` +Q: "You're already connected to a cluster ( — maybe set up by someone else?). Use that instead of creating a new one?" + Options: + - "Yes, use it" — stop here; they're already logged in, continue the journey on that cluster + - "No, create my own" → continue +``` + This plugin assumes one cluster, many apps in their own namespaces. Only create a second cluster if the user is sure. ## Step 2 — Authenticate diff --git a/skills/deploy-app/SKILL.md b/skills/deploy-app/SKILL.md index 0522ebd..a031862 100644 --- a/skills/deploy-app/SKILL.md +++ b/skills/deploy-app/SKILL.md @@ -1,7 +1,6 @@ --- name: deploy-app description: Generates Kubernetes manifests (Namespace, Deployment, Service) for a containerized app and deploys them to the cluster with oc apply. Use when the user wants to "deploy my app", "ship my app", "run my app on the cluster", or after prepare-app has confirmed they have a containerized image. Defaults to a one-app-per-namespace layout so the same cluster can host many apps cleanly. -user-invocable: true allowed-tools: - AskUserQuestion - Bash(oc whoami*) @@ -11,7 +10,6 @@ allowed-tools: - Bash(oc rollout*) - Bash(oc describe*) - Bash(oc logs*) - - Bash(oc delete*) - Bash(mkdir *) - Read - Write diff --git a/skills/expose-app/SKILL.md b/skills/expose-app/SKILL.md index 189216d..051de4a 100644 --- a/skills/expose-app/SKILL.md +++ b/skills/expose-app/SKILL.md @@ -1,7 +1,6 @@ --- name: expose-app description: Gives a deployed app a public or internal URL by creating an HTTPRoute on the Intility Developer Platform. Use when the user says "expose my app", "give my app a URL", "make my app accessible", "set up ingress", "create a route", or after deploy-app finishes and the user wants the app reachable. -user-invocable: true allowed-tools: - AskUserQuestion - Bash(oc whoami*) @@ -9,8 +8,7 @@ allowed-tools: - Bash(oc apply*) - Bash(oc describe*) - Bash(oc delete httproute*) - - Bash(sed *) - - Bash(curl *) + - Bash(curl -s -o /dev/null*) - Read - Write - Edit diff --git a/skills/getting-started/SKILL.md b/skills/getting-started/SKILL.md index bee04b5..7a7b06e 100644 --- a/skills/getting-started/SKILL.md +++ b/skills/getting-started/SKILL.md @@ -1,7 +1,6 @@ --- name: getting-started description: Entry point for getting an app running on the Intility Developer Platform. Use when the user says things like "help me deploy", "get me started with Intility", "I want to run my app on the platform", "I'm new to Kubernetes and need to ship something", or "what do I do next?". Figures out where the user is in the journey (no cluster yet → cluster but no app → app deployed but no URL → ready to update) and routes to the right skill. -user-invocable: true allowed-tools: - AskUserQuestion - Bash(command -v *) @@ -55,12 +54,14 @@ From the results, classify the situation: | Situation | Signal | |---|---| | Not logged in to `indev` | `indev account show` fails | -| No cluster yet | `indev cluster list` returns empty / no clusters | +| No cluster yet | `indev cluster list` returns empty / no clusters **and** `oc whoami` fails | | Has a cluster, not logged in | Cluster exists, `oc whoami` fails | | Logged in, no app deployed | `oc whoami` works, but the user hasn't mentioned an app namespace | | Has an app, needs a URL | User says it's deployed but not reachable | | Wants to update | User mentions a new image / new version | +**`oc whoami` working beats an empty `indev cluster list`.** Clusters are sometimes provisioned by platform admins or a colleague, so they don't show up in *this user's* `indev cluster list`. If `oc whoami` succeeds, the user has a cluster — treat the situation as "has a cluster, logged in" and never route to `create-cluster`. Use `oc whoami --show-server` to tell them which cluster they're connected to. + ## Step 2 — Confirm where they want to go If the situation is obvious from the user's message, just continue. Otherwise ask one short question: diff --git a/skills/login/SKILL.md b/skills/login/SKILL.md index 8c78bf7..7301379 100644 --- a/skills/login/SKILL.md +++ b/skills/login/SKILL.md @@ -1,7 +1,6 @@ --- name: login description: Logs the user into their Intility Developer Platform cluster so they can run kubectl/oc commands against it. Use when the user asks to "log in", "log into the cluster", "connect to my cluster", "oc login", or when another skill needs cluster access and the user is not authenticated. -user-invocable: true allowed-tools: - AskUserQuestion - Bash(indev cluster list*) diff --git a/skills/prepare-app/SKILL.md b/skills/prepare-app/SKILL.md index 3f12e65..91fea8c 100644 --- a/skills/prepare-app/SKILL.md +++ b/skills/prepare-app/SKILL.md @@ -1,13 +1,11 @@ --- name: prepare-app description: Verifies that the user's app is containerized and that an image exists in a registry the cluster can pull from, before deploying. Use when the user wants to deploy something but you don't yet know if they have a Dockerfile or a pushed image, or when the deploy-app skill needs an image reference and doesn't have one yet. -user-invocable: true allowed-tools: - AskUserQuestion - - Bash(ls *) - - Bash(find *) - Bash(docker images*) - Bash(docker manifest inspect*) + - Glob - Read --- @@ -23,10 +21,10 @@ If both are true, hand off to `deploy-app`. Otherwise, tell the user the smalles ## Step 1 — Look for a Dockerfile -Search the project root and one level down: +Search the project root and one level down using the Glob tool: -```bash -find . -maxdepth 2 \( -name Dockerfile -o -name Containerfile \) 2>/dev/null +``` +Glob: {Dockerfile,Containerfile,*/Dockerfile,*/Containerfile} ``` If found, note the path. If not: diff --git a/skills/status/SKILL.md b/skills/status/SKILL.md index 2cffc7f..45ca7c3 100644 --- a/skills/status/SKILL.md +++ b/skills/status/SKILL.md @@ -1,13 +1,11 @@ --- name: status description: Shows a summary of what the user has on the Intility Developer Platform — their cluster, deployed apps, and the URLs those apps are exposed on. Use when the user asks "what's deployed?", "what do I have running?", "what apps are on my cluster?", "what's the URL for X?", "show me my cluster", or comes back after a break and needs a refresher. -user-invocable: true allowed-tools: - Bash(indev cluster list*) - Bash(oc whoami*) - Bash(oc get*) - Bash(grep *) - - Bash(sed *) --- # Status @@ -43,9 +41,11 @@ If it errors, tell the user and suggest the `login` skill. Show the cluster name If it works, also grab the cluster name from the API URL — useful for showing hostnames: ```bash -oc whoami --show-server | sed 's|https://api[-.]||' | sed 's|[.:].*||' +oc whoami --show-server ``` +The server URL looks like `https://api..:6443` — read the cluster name out of it yourself; no text-processing pipeline needed. + ## Step 3 — Deployments List all deployments excluding platform/system namespaces: diff --git a/skills/update-image/SKILL.md b/skills/update-image/SKILL.md index c621fda..cd2dcf3 100644 --- a/skills/update-image/SKILL.md +++ b/skills/update-image/SKILL.md @@ -1,7 +1,7 @@ --- name: update-image description: Updates the container image on an already-deployed app to a new version. Use when the user says "update my app", "deploy a new version", "ship v2", "bump the image to X", or otherwise wants to roll out a new build of something already running on the cluster. -user-invocable: true +argument-hint: "[app] [new-image-or-tag]" allowed-tools: - AskUserQuestion - Bash(oc whoami*) From d37ffed4b325a57b6d7f1931b7583ef8f581a844 Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 10 Jun 2026 09:43:26 +0200 Subject: [PATCH 2/2] ci: pin actions to full commit SHAs per org policy Co-Authored-By: Claude Fable 5 --- .github/workflows/release-please.yml | 2 +- .github/workflows/validate.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index bc8cfaa..b76ee24 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -12,7 +12,7 @@ jobs: release-please: runs-on: ubuntu-latest steps: - - uses: googleapis/release-please-action@v4 + - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 with: config-file: .release-please-config.json manifest-file: .release-please-manifest.json diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 3a54f0c..3015e5b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,8 +9,8 @@ jobs: validate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 - name: Install Claude Code