From 5703345ba873469c851774e6ec29111f3d44ccb3 Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 10 Jun 2026 10:31:41 +0200 Subject: [PATCH] feat: from-zero path for citizen developers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prepare-app no longer dead-ends users who've never used Docker, GitHub, or a registry: a new build-and-push walkthrough covers Docker Desktop, a free GitHub account, the classic PAT, login, build (incl. the Apple Silicon --platform gotcha), and push — one command at a time. The port question now tries to detect the answer from the code first and just confirms. Tone rules in getting-started/prepare-app make 'never assume Docker/GitHub/git/k8s experience' explicit, brew install hints added for missing CLIs, and usage examples rewritten to show the guided flow instead of 'come back when you've pushed'. Co-Authored-By: Claude Fable 5 --- README.md | 3 + skills/getting-started/SKILL.md | 7 +- skills/prepare-app/SKILL.md | 17 +++- .../prepare-app/references/build-and-push.md | 65 +++++++++++++ .../prepare-app/references/usage-examples.md | 97 +++++++++++++------ skills/update-image/SKILL.md | 2 +- 6 files changed, 155 insertions(+), 36 deletions(-) create mode 100644 skills/prepare-app/references/build-and-push.md diff --git a/README.md b/README.md index fa415a8..e1767d9 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ ## Features +- **From zero to URL** — never used Docker, GitHub, or Kubernetes? The skills meet you where you are, one command at a time, including building and pushing your first image - **Create a cluster** in one prompt — sensible defaults, no preset/zone/autoscaling questions - **Deploy any container** — Claude writes the Namespace, Deployment, and Service for you - **Real URLs via HTTPRoute** — `internal` by default, with an explicit security check before exposing anything publicly @@ -54,6 +55,8 @@ Claude: [creates HTTPRoute on the internal gateway] Live at http://shop.apps.example.com — try it out. ``` +Don't have an image yet — or not sure what an image is? Start the same way. The plugin notices what's missing and walks you through containerizing, building, and pushing first. + ## What's in the box Eight composable skills. All are user-invocable, so you can ask for any of them directly — or just describe what you want and the right one runs. diff --git a/skills/getting-started/SKILL.md b/skills/getting-started/SKILL.md index 7a7b06e..ed99156 100644 --- a/skills/getting-started/SKILL.md +++ b/skills/getting-started/SKILL.md @@ -32,9 +32,9 @@ command -v oc >/dev/null 2>&1 && echo "oc: ok" || echo "oc: MISSING" command -v docker >/dev/null 2>&1 && echo "docker: ok" || echo "docker: missing (optional)" ``` -- **`indev` missing** → stop. Send the user to https://developers.intility.com to install it. Nothing else works without this. -- **`oc` missing** → stop. Same page has install instructions. -- **`docker` missing** → fine to continue. Only `prepare-app` uses it, and that's optional. +- **`indev` missing** → stop. On macOS the quickest path is `brew install intility/tap/indev`; otherwise https://developers.intility.com has instructions. Nothing else works without this. +- **`oc` missing** → stop. macOS: `brew install openshift-cli`; otherwise same page as above. +- **`docker` missing** → fine to continue. Only `prepare-app` uses it, and only when an image still needs to be built or checked — it helps the user install Docker at that point. If everything is present, don't say anything — move on silently. Only narrate the check if something is missing. @@ -109,6 +109,7 @@ To add another app, just ask: "deploy another app" — it'll go in its own names ## Tone reminders - Plain language. Avoid "namespace", "manifest", "ingress" on first mention — say what they *do* first, then introduce the term once. +- Never assume prior Docker, GitHub, git, or Kubernetes experience. Many users are shipping their very first app — that's exactly who this plugin is for, and the skills have from-zero paths for each gap (e.g. `prepare-app` can walk them from "no Dockerfile, no registry" to a pushed image). - One command at a time. Don't dump three commands and hope they pick one. - Don't apologize for asking questions. One question, then move on. - If they're stuck, suggest the next concrete step. Don't open with troubleshooting trees. diff --git a/skills/prepare-app/SKILL.md b/skills/prepare-app/SKILL.md index a7a00f7..b236ede 100644 --- a/skills/prepare-app/SKILL.md +++ b/skills/prepare-app/SKILL.md @@ -37,13 +37,15 @@ Q: "I couldn't find a Dockerfile. Do you have one?" - "I have an image already, no Dockerfile needed" ``` -If "No, not yet": don't try to write one for them on the spot — ask what the app is (language, framework, how it starts), then draft a minimal `Dockerfile` using one of the templates in [references/minimal-dockerfile.md](references/minimal-dockerfile.md). Pick the closest match, adapt names and ports to their app, drop in the file, and stop. They build and push it themselves — this plugin doesn't run `docker build`. +If "No, not yet": don't try to write one for them on the spot — ask what the app is (language, framework, how it starts), then draft a minimal `Dockerfile` using one of the templates in [references/minimal-dockerfile.md](references/minimal-dockerfile.md). Pick the closest match, adapt names and ports to their app, and drop in the file. + +Then walk them through building and pushing it using [references/build-and-push.md](references/build-and-push.md) — one command at a time, they run each one themselves (this plugin doesn't run `docker build`). Don't assume they've used Docker, GitHub, or a registry before; the walkthrough covers the from-zero path including getting a token. After they confirm the image is pushed, continue with Step 2. ## Step 2 — Confirm there's a pushed image -This plugin doesn't build or push images for the user — that varies too much by registry. We just need an image reference. +This plugin doesn't run `docker build`/`docker push` for the user — but it does guide them through running those themselves (see Step 1 / the build-and-push walkthrough). What this step needs to end with is an image reference. ``` Q: "What's the image reference for your app?" @@ -55,7 +57,7 @@ If they don't know what an image reference is, give them one sentence: > It's the address where your built image lives. After `docker push`, it's the same string you `docker push`-ed to — registry + repo + tag. -If they haven't pushed yet, point them at the registry they're using (or suggest `ghcr.io` if they're on GitHub) and **stop here**. Tell them: "Once you've run `docker push`, come back and we'll deploy it." Do not try to build or push for them. +If they haven't pushed yet, don't just send them away — offer to walk them through it right now using [references/build-and-push.md](references/build-and-push.md). It covers the full from-zero path: Docker Desktop, a free GitHub account if they don't have one (no git knowledge needed — the account is just the key to the registry), token, login, build, push. One command at a time; they run each themselves. If their team already has a different registry, the same steps apply with that registry's address and login. ## Step 3 — Optional: sanity check the image exists @@ -71,7 +73,10 @@ Skip this step if `docker` isn't installed locally — it's a nice-to-have, not ## Step 4 — What port does the app listen on? -This is the single most-forgotten thing later. Ask now: +This is the single most-forgotten thing later — and "what port?" is a question many users genuinely can't answer. So **look before you ask**: check the `Dockerfile` for `EXPOSE`, and the code for the usual suspects (`package.json` start script, `app.listen(...)`, `PORT` env defaults, framework config). + +- **Found one** → confirm it in one line: "Looks like your app listens on port 3000 — right?" Most users just say yes. +- **Can't tell** → ask, with hints: ``` Q: "What port does your app listen on inside the container?" @@ -82,6 +87,8 @@ Q: "What port does your app listen on inside the container?" - Other (free text) ``` +If they have no idea even with the hints, offer to look through the code together — it's in there somewhere. + ## Step 5 — Hand off Pass forward to `deploy-app`: @@ -96,9 +103,11 @@ app: ## Tone - Don't lecture them on containers. If they don't know what an image is, give one sentence, then move on. +- Never assume they've used Docker, GitHub, or git before. Check with one short question, then meet them where they are — the build-and-push walkthrough exists exactly for this. - If they're missing a Dockerfile and the conversation goes deep, *stop* and write a Dockerfile in a separate turn. Don't conflate "deploy" with "containerize from scratch" — these are different sessions. ## References - [references/minimal-dockerfile.md](references/minimal-dockerfile.md) — copy-paste Dockerfile templates for Node, Python, Go, and static sites +- [references/build-and-push.md](references/build-and-push.md) — from-zero walkthrough: Docker Desktop, GitHub account, token, login, build, push - [references/usage-examples.md](references/usage-examples.md) — typical conversations (ready to go, no Dockerfile, private registry, image not pushed) diff --git a/skills/prepare-app/references/build-and-push.md b/skills/prepare-app/references/build-and-push.md new file mode 100644 index 0000000..badb650 --- /dev/null +++ b/skills/prepare-app/references/build-and-push.md @@ -0,0 +1,65 @@ +# Build and Push Your First Image + +A walkthrough for users who have never built or pushed a container image. Guide them through it **one command at a time** — show a command, let them run it (or run it for them only if they explicitly ask), confirm it worked, then show the next. Never paste the whole list at once. + +The flow below uses GitHub's registry (`ghcr.io`) because it's free and most common. If their team already has another registry, the same steps apply — only the address and login change. + +## Before starting, check quietly + +- **Docker installed?** `command -v docker`. If missing: they need Docker Desktop — https://www.docker.com/products/docker-desktop/ — install, open it once, come back. (On macOS: `brew install --cask docker` also works.) +- **GitHub account?** Ask in one line. If they don't have one, it's free at https://github.com/signup — they don't need to know git or use repositories; the account is just the key to the registry. + +## Step 1 — Get a token to log in with + +ghcr.io doesn't accept your GitHub password. You need a **classic personal access token**: + +1. Go to https://github.com/settings/tokens → "Generate new token (classic)" +2. Name it something like `registry`, tick the **`write:packages`** scope (this auto-ticks `read:packages`) +3. Generate, and copy the token (starts with `ghp_`) — you won't see it again + +Tell the user to keep it somewhere safe; it's also what `deploy-app` will ask for later so the cluster can pull the image. + +## Step 2 — Log Docker in to the registry + +```bash +docker login ghcr.io -u +``` + +When it asks for a password, paste the token from Step 1 — not the GitHub password. Success looks like `Login Succeeded`. + +## Step 3 — Build the image + +Run from the directory with the `Dockerfile`: + +```bash +docker build -t ghcr.io//:v1 . +``` + +One-line explanation to give: *"`-t` names the image — the name doubles as the address it will be uploaded to. `v1` is the version tag; you'll bump it for each release."* + +Notes: +- The name must be **all lowercase** — `ghcr.io/Me/MyApp` is rejected. +- Don't forget the trailing `.` — it means "build from this directory". +- On Apple Silicon Macs, build for the cluster's architecture: add `--platform linux/amd64`. + +## Step 4 — Push it + +```bash +docker push ghcr.io//:v1 +``` + +When the progress bars finish, the image is in the registry. That full string — `ghcr.io//:v1` — is the **image reference** the rest of the journey needs. + +## Good to know afterwards + +- **ghcr images are private by default.** That's fine — `deploy-app` sets up cluster pull access with one question (it'll ask for the same username + token). +- **Shipping a new version later:** rebuild and push with a new tag (`:v2`), then say "update to v2" — the `update-image` skill does the rest. + +## When things go wrong + +| Symptom | Likely cause | +|---|---| +| `denied` on push | Token missing the `write:packages` scope — make a new one | +| `unauthorized` on login | Pasted the GitHub password instead of the token | +| `invalid reference format` / repository name errors | Uppercase letters in the image name — lowercase everything | +| Build fails | That's a Dockerfile/app problem, not a registry problem — read the error together and fix the Dockerfile | diff --git a/skills/prepare-app/references/usage-examples.md b/skills/prepare-app/references/usage-examples.md index c3a56ba..1e2c435 100644 --- a/skills/prepare-app/references/usage-examples.md +++ b/skills/prepare-app/references/usage-examples.md @@ -5,7 +5,7 @@ ``` You: My app is at ghcr.io/me/shop:v1, listens on 3000. -Claude: [find . -name Dockerfile → ./Dockerfile found] +Claude: [Glob Dockerfile → ./Dockerfile found] [docker manifest inspect ghcr.io/me/shop:v1 → ok, public] Image looks good. Port 3000. Handing off to deploy-app. @@ -13,40 +13,68 @@ Claude: [find . -name Dockerfile → ./Dockerfile found] --- -## Example 2 — No Dockerfile yet +## Example 2 — Never deployed anything before + +User has code, no Dockerfile, no Docker, no GitHub account. The skill walks the whole path — one command at a time, the user runs each one. ``` -You: I want to deploy my Node app but I don't have a Dockerfile. +You: I built a little internal tool in Node. I've never deployed anything. + Can you get it online? -Claude: What does your app do, and how do you start it locally? -You: It's a Next.js app. `npm start` runs it on port 3000. +Claude: Absolutely — we'll do it step by step. First I'll package your app so + the platform can run it. How do you start it locally? +You: npm start, it says it's on localhost:3000. -Claude: [reads templates from references/minimal-dockerfile.md] - [writes ./Dockerfile + .dockerignore] +Claude: [writes ./Dockerfile from references/minimal-dockerfile.md, port 3000] - Here's a starter Dockerfile that should work. Run: - docker build -t ghcr.io//:v1 . - docker push ghcr.io//:v1 + Done — this file describes how to run your app anywhere. Next we need + somewhere to upload it. Do you have a GitHub account? +You: No. - Then come back and we'll deploy it. -``` +Claude: No problem — it's free and you won't need to learn git; the account is + just the key to GitHub's image storage. Create one at + github.com/signup, then tell me your username. +You: ok, I'm "annab" + +Claude: Great. Now a token so Docker can log in as you: + github.com/settings/tokens → "Generate new token (classic)" → + tick "write:packages" → Generate. Copy the ghp_... string. +You: got it + +Claude: Run this, and paste the token when it asks for a password: + + docker login ghcr.io -u annab + +You: Login Succeeded + +Claude: Now build: + + docker build -t ghcr.io/annab/mytool:v1 . + +You: done, lots of output but it finished + +Claude: Last one — upload it: + + docker push ghcr.io/annab/mytool:v1 -The skill stops here. Building and pushing is the user's job. +You: done! + +Claude: Your app now lives at ghcr.io/annab/mytool:v1. It's private by + default, which is fine — I'll set up cluster access when we deploy. + Handing off to deploy-app. +``` --- ## Example 3 — Private registry ``` -You: Image is at private.registry.example.com/team/app:v1, port 8080. +You: Image is at ghcr.io/team/app:v1, port 8080. It's private. Claude: [docker manifest inspect → unauthorized] - Looks like that image is in a private registry. We'll need to set up an - image pull secret in the cluster — deploy-app will handle that, just be - ready with your registry username + access token. - - Continuing. + Noted — deploy-app will set up cluster pull access (one question: + username + token, once for the whole cluster). Continuing. ``` --- @@ -56,21 +84,34 @@ Claude: [docker manifest inspect → unauthorized] ``` You: I have a Dockerfile but I haven't pushed anywhere. -Claude: I need an image reference (something like ghcr.io//:v1) before - we can deploy. The cluster pulls from a registry, not from your laptop. +Claude: The cluster pulls your app from a registry, not from your laptop — + so let's get it uploaded. It's three commands and I'll walk you + through each. Do you have a GitHub account? +You: yes + +Claude: [continues with the token → login → build → push walkthrough from + references/build-and-push.md, one command at a time] +``` + +--- + +## Example 5 — Port detected from the code + +``` +You: Deploy this, image is pushed at ghcr.io/me/api:v1. + +Claude: [Glob Dockerfile → found; reads it → EXPOSE 8000] - Pick a registry — GitHub's ghcr.io is free for public repos and works - with your GitHub login. Then: - docker build -t ghcr.io//:v1 . - docker push ghcr.io//:v1 + Looks like your app listens on port 8000 — right? +You: yes - Once it's pushed, come back and tell me the image reference. +Claude: Handing off to deploy-app. ``` --- ## What this skill won't do -- Run `docker build` or `docker push` for you +- Run `docker build` or `docker push` itself — you run them, it guides you through each one - Write a Dockerfile without you telling it what the app is -- Set up a registry account +- Create accounts for you (but it will point you at exactly the right signup and token pages) diff --git a/skills/update-image/SKILL.md b/skills/update-image/SKILL.md index cd2dcf3..5e3cea0 100644 --- a/skills/update-image/SKILL.md +++ b/skills/update-image/SKILL.md @@ -131,4 +131,4 @@ See [references/usage-examples.md](references/usage-examples.md) for typical con - Don't use `kubectl edit` / `oc edit` — opens an editor, fragile. - Don't re-apply the whole `deployment.yaml` from disk unless the local file is already updated. Otherwise you'll roll back any image bumps that happened via `oc set image`. -- Don't suggest `latest` as a tag. Encourage immutable tags (commit SHAs, version numbers). +- Don't suggest `latest` as a tag. Encourage tags that never move — version numbers like `v2`, `v3` — so it's always clear which build is running and rollback has something to roll back to.