From 6a78770ef3d3874b853cf151912434cafb7255fd Mon Sep 17 00:00:00 2001 From: John Collier Date: Thu, 25 Jun 2026 11:18:00 -0400 Subject: [PATCH 1/9] chore(agent-readiness): bootstrap basic AGENTS.md and minor repo updates Signed-off-by: John Collier --- .claude/settings.json | 15 ++++++++++++++ .gitignore | 3 +++ AGENTS.md | 48 +++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + Makefile | 24 ++++++++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 .claude/settings.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 Makefile diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..8e44fb02 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit|Write", + "hooks": [ + { + "type": "command", + "command": "FILE=\"$CLAUDE_FILE_PATH\"; case \"$FILE\" in *.yaml|*.yml) npx --yes dclint \"$FILE\" 2>/dev/null || true ;; *.sh) shellcheck \"$FILE\" 2>/dev/null || true ;; esac" + } + ] + } + ] + } +} diff --git a/.gitignore b/.gitignore index c891d088..7fd9e47d 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ generated/ **/.DS_Store .idea +*.swp +*.swo +.vscode/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..52049ccd --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,48 @@ +# rhdh-local + +Red Hat Developer Hub (RHDH) Local — a Docker/Podman Compose setup for running RHDH locally for development and testing. Not a substitute for production RHDH; intended for individual developer use on a laptop/desktop. + +## Build & Test Commands + +- Start: `podman compose up -d` (or `docker compose up -d`) +- Stop RHDH only: `podman compose stop rhdh` +- Stop all: `podman compose down` +- Teardown (including volumes): `podman compose down --volumes` +- Reinstall plugins then restart RHDH: `podman compose run install-dynamic-plugins && podman compose stop rhdh && podman compose start rhdh` +- Lint all compose files: `npx dclint .` +- Lint single compose file: `npx dclint ` +- Lint shell scripts: `shellcheck *.sh` +- Lint single shell script: `shellcheck ` + +## Single-File Verification + +- Compose/YAML file: `npx dclint ` +- Shell script: `shellcheck ` + +## Key Conventions + + + +## Architecture + + + +## PR Conventions + +- Conventional Commits are used: `fix:`, `feat:`, `chore:`, `ci:`, `docs:`, etc. +- Scope examples: `nightly`, `deps`, `lightspeed`, `plugins` +- Agent-assisted commits should include an `Assisted-by: ` footer +- Report issues to Jira project RHIDP with Component: **RHDH Local** + +## Pattern References + +- Compose overlay: see `compose-with-corporate-proxy.yaml` for how to extend `compose.yaml` +- Dynamic plugins config: see files in `configs/dynamic-plugins/` for plugin configuration patterns +- Orchestrator integration: see `orchestrator/compose.yaml` for adding services via overlay +- Shell utility scripts: see `prepare-and-install-dynamic-plugins.sh` and `wait-for-plugins-and-start.sh` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..43c994c2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0bdd2d72 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: start stop restart clean plugins-install lint + +## Start RHDH Local (default Podman; set TOOL=docker to use Docker) +TOOL ?= podman + +start: + $(TOOL) compose up -d + +stop: + $(TOOL) compose down + +restart: stop start + +clean: + $(TOOL) compose down --volumes + +plugins-install: + $(TOOL) compose run install-dynamic-plugins + $(TOOL) compose stop rhdh + $(TOOL) compose start rhdh + +lint: + npx dclint . + shellcheck *.sh From 3f4699f075f0db51dca1fe0d911ba46382b1de09 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Fri, 6 Nov 2026 23:15:49 +0100 Subject: [PATCH 2/9] chore(agent-readiness): make lint the entry point and document make targets The committed Claude hook read CLAUDE_FILE_PATH, a variable Claude Code does not export, so it silently did nothing on every edit. Drop it and make `make lint` the single entry point instead, running dclint and shellcheck from pinned container images so no Node.js, npx, or host linter is needed. Align the Makefile with the documented lifecycle while there: `stop` and `restart` now act on the rhdh service instead of tearing down the whole project, `down` is the full teardown, `help` is the default goal, and OVERLAYS takes short names (db, corporate-proxy, dynamic-plugins-root, orchestrator) or any compose file path, with compose.yaml always named explicitly so an overlay can never be run on its own. AGENTS.md now documents the make targets, the overlays, and the tests/ validators that CI actually runs, since the previous lint-only guidance left no way to verify a compose change. Assisted-by: DeepSeek V4.1 Flash Signed-off-by: Armel Soro --- .claude/settings.json | 15 -------- AGENTS.md | 35 ++++++++++++------- Makefile | 80 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 86 insertions(+), 44 deletions(-) delete mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 8e44fb02..00000000 --- a/.claude/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hooks": { - "PostToolUse": [ - { - "matcher": "Edit|Write", - "hooks": [ - { - "type": "command", - "command": "FILE=\"$CLAUDE_FILE_PATH\"; case \"$FILE\" in *.yaml|*.yml) npx --yes dclint \"$FILE\" 2>/dev/null || true ;; *.sh) shellcheck \"$FILE\" 2>/dev/null || true ;; esac" - } - ] - } - ] - } -} diff --git a/AGENTS.md b/AGENTS.md index 52049ccd..6b95d197 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,22 +2,30 @@ Red Hat Developer Hub (RHDH) Local — a Docker/Podman Compose setup for running RHDH locally for development and testing. Not a substitute for production RHDH; intended for individual developer use on a laptop/desktop. +Everything below is available through the `Makefile`; run `make help` for the full list. Commands default to Podman — pass `TOOL=docker` for Docker. `make lint` runs both linters from pinned container images (`DCLINT_IMAGE`, `SHELLCHECK_IMAGE`), so no Node.js, npx, or host linter installation is required. + ## Build & Test Commands -- Start: `podman compose up -d` (or `docker compose up -d`) -- Stop RHDH only: `podman compose stop rhdh` -- Stop all: `podman compose down` -- Teardown (including volumes): `podman compose down --volumes` -- Reinstall plugins then restart RHDH: `podman compose run install-dynamic-plugins && podman compose stop rhdh && podman compose start rhdh` -- Lint all compose files: `npx dclint .` -- Lint single compose file: `npx dclint ` -- Lint shell scripts: `shellcheck *.sh` -- Lint single shell script: `shellcheck ` +- Start: `make start` (`podman compose up -d`) +- Stop RHDH only: `make stop` (`podman compose stop rhdh`) +- Restart RHDH only, for configuration changes: `make restart` +- Reinstall plugins, then restart RHDH: `make plugins-install` +- Stop and remove all containers: `make down` +- Teardown including volumes: `make clean` +- Compose overlays: `make start OVERLAYS="db orchestrator"` — space-separated names, applied on top of `compose.yaml`, which the Makefile then names explicitly. Available names: `db`, `corporate-proxy`, `dynamic-plugins-root`, `orchestrator`; any `*.yaml` path also works for personal overrides. A local `compose.override.yaml` only applies when `OVERLAYS` is empty. +- Lint tracked compose files and shell scripts: `make lint` + +## Verification + +CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run whichever covers what you changed. All of the lint checks need only the container engine; the runtime validators need RHDH running plus `yq`, `jq`, and `curl`. -## Single-File Verification +- Compose change: render the config for the overlay you touched, e.g. `podman compose -f compose.yaml -f compose-with-db.yaml config` +- Dynamic plugins actually load (RHDH must be running; needs `yq`, `jq`, `curl`): `./tests/validate-loaded-plugins.sh` +- Intelligent Assistant: `./tests/validate-intelligent-assistant-compose.sh` and `./tests/validate-intelligent-assistant-runtime.sh` +- Single compose file: `podman run --rm -v "$PWD":/app:ro,z -w /app docker.io/zavoloklom/dclint:3.1.0 `, using the same image as `make lint` +- Single shell script: `podman run --rm -v "$PWD":/app:ro,z -w /app docker.io/koalaman/shellcheck:v0.11.0 `, using the same image as `make lint` -- Compose/YAML file: `npx dclint ` -- Shell script: `shellcheck ` +`make lint` and repo-wide dclint only cover git-tracked files. Developer-specific `*.local.yaml` overrides are deliberately not linted, so lint findings never point at files that are not in the repository. ## Key Conventions @@ -46,3 +54,6 @@ Red Hat Developer Hub (RHDH) Local — a Docker/Podman Compose setup for running - Dynamic plugins config: see files in `configs/dynamic-plugins/` for plugin configuration patterns - Orchestrator integration: see `orchestrator/compose.yaml` for adding services via overlay - Shell utility scripts: see `prepare-and-install-dynamic-plugins.sh` and `wait-for-plugins-and-start.sh` +- Local overrides: copy values from `default.env` into `.env` (git-ignored) to pin images, tags, and feature flags instead of editing compose files +- CI verification: see `.github/actions/rhdh-local-compose-test/action.yaml` and `tests/` +- User-facing docs (rendered as TechDocs): see `docs/`, plus `README.md` for the quick commands diff --git a/Makefile b/Makefile index 0bdd2d72..8570702f 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,70 @@ -.PHONY: start stop restart clean plugins-install lint - -## Start RHDH Local (default Podman; set TOOL=docker to use Docker) +# RHDH Local — common developer tasks. Run `make help` for the list. +# +# TOOL container tool to use, default podman (TOOL=docker to use Docker) +# OVERLAYS overlays applied on top of compose.yaml, space-separated. +# Accepts the named overlays below or a path to any compose file, +# e.g. make start OVERLAYS="db orchestrator" +# DCLINT_IMAGE dclint image used by `make lint`, pinned to a release tag +# SHELLCHECK_IMAGE shellcheck image used by `make lint`, pinned to a release tag +# TOOL ?= podman +OVERLAYS ?= + +# Named overlays, so nobody has to remember compose file names. +OVERLAY_NAMES := db corporate-proxy dynamic-plugins-root orchestrator +OVERLAY_db := compose-with-db.yaml +OVERLAY_corporate-proxy := compose-with-corporate-proxy.yaml +OVERLAY_dynamic-plugins-root := compose-dynamic-plugins-root.yaml +OVERLAY_orchestrator := orchestrator/compose.yaml + +unknown_overlays := $(filter-out $(OVERLAY_NAMES) %.yaml,$(OVERLAYS)) +ifneq ($(strip $(unknown_overlays)),) +$(error Unknown OVERLAYS entry: $(unknown_overlays) (use: $(OVERLAY_NAMES), or a *.yaml path)) +endif + +OVERLAY_FILES := $(foreach overlay,$(OVERLAYS),$(if $(filter %.yaml,$(overlay)),$(overlay),$(OVERLAY_$(overlay)))) +# Compose only auto-detects compose.yaml and compose.override.yaml when no -f is +# given, so naming an overlay means naming the base file too. +COMPOSE_ARGS := $(if $(strip $(OVERLAYS)),-f compose.yaml $(addprefix -f ,$(OVERLAY_FILES))) +COMPOSE := $(strip $(TOOL) compose $(COMPOSE_ARGS)) + +DCLINT_IMAGE ?= docker.io/zavoloklom/dclint:3.1.0 +SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0 +LINT_MOUNT := -v "$(CURDIR)":/app:ro,z -w /app + +.PHONY: help start stop restart plugins-install down clean lint + +.DEFAULT_GOAL := help + +help: ## Show this help + @grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) \ + | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-17s\033[0m %s\n", $$1, $$2}' + @printf '\n OVERLAYS: %s (or a path to any compose file)\n' "$(OVERLAY_NAMES)" + @printf ' e.g. make start OVERLAYS="db orchestrator"\n' + +start: ## Start RHDH Local + $(COMPOSE) up -d -start: - $(TOOL) compose up -d +stop: ## Stop RHDH only, leaving the containers in place + $(COMPOSE) stop rhdh -stop: - $(TOOL) compose down +restart: ## Restart RHDH only, for configuration changes + $(COMPOSE) stop rhdh + $(COMPOSE) start rhdh -restart: stop start +plugins-install: ## Reinstall dynamic plugins, then restart RHDH + $(COMPOSE) run install-dynamic-plugins + $(COMPOSE) stop rhdh + $(COMPOSE) start rhdh -clean: - $(TOOL) compose down --volumes +down: ## Stop and remove all containers and the network, keeping volumes + $(COMPOSE) down -plugins-install: - $(TOOL) compose run install-dynamic-plugins - $(TOOL) compose stop rhdh - $(TOOL) compose start rhdh +clean: ## Stop everything and remove volumes + $(COMPOSE) down --volumes -lint: - npx dclint . - shellcheck *.sh +lint: ## Lint the tracked compose files and shell scripts + $(TOOL) run --rm $(LINT_MOUNT) $(DCLINT_IMAGE) \ + $(shell git ls-files 'compose*.yaml' 'orchestrator/compose*.yaml') + $(TOOL) run --rm $(LINT_MOUNT) $(SHELLCHECK_IMAGE) \ + $(shell git ls-files '*.sh') From ec8a75f1b27d99781dfc55f24889be1b94c1e17e Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Fri, 6 Nov 2026 23:19:58 +0100 Subject: [PATCH 3/9] docs(agent-readiness): document repo conventions in AGENTS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the maintainer TODOs with the conventions and architecture an agent cannot infer from the code alone: the main/dev/release-x.y branching model and the PR warning the branch-target workflow posts, the TechDocs nav requirement, the rule that user configuration stays in git-ignored *.local.yaml and *.override.yaml files, and the plugin configuration precedence where the selected file replaces the default list rather than merging into it. Record how startup actually works as well: the two-stage install-dynamic-plugins → rhdh handoff, the runtime app-config layering order, the shared volumes and bind mounts, and the fact that tests/ holds validators that need a running instance. Also note where the lightly discovered pieces live (orchestrator/, intelligent-assistant/, and the generated Lightspeed configs), and point at the plugin development and operating guides from Pattern References. Assisted-by: DeepSeek V4.1 Flash Signed-off-by: Armel Soro --- AGENTS.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6b95d197..a92d4c9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,17 +29,24 @@ CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run ## Key Conventions - +- **Branching**: `main` is the latest stable GA release, `dev` carries development for the next release, `release-x.y` stabilizes a release and takes its patch fixes. Target `dev` for features, docs, and dependency updates; `release-x.y` for bug fixes on a supported release; do not target `main`, which maintainers update by merge and cherry-pick. `.github/workflows/branch-target-check.yaml` comments a warning on every PR opened against `main`. +- **Docs are part of the product**: everything under `docs/` is rendered as TechDocs through `mkdocs.yaml`, so a new page also needs a `nav` entry. `docs/`, `mkdocs.yaml`, and `catalog-info.yaml` are mounted read-only and copied into a writable workdir at startup, so restart `rhdh` to preview edits. +- **User configuration is never committed**: `.env`, `configs/**/*.override.yaml`, `configs/**/*.local.yaml`, and `compose.override.yaml` are git-ignored. Change the tracked `*.example.yaml` counterparts instead; CI's "user config" matrix copies them into place verbatim, so they must stay valid and self-contained. +- **Dynamic plugin configuration replaces, it does not merge**: `configs/dynamic-plugins/dynamic-plugins.override.yaml` wins over the deprecated `configs/dynamic-plugins.yaml`, which wins over `configs/dynamic-plugins/dynamic-plugins.yaml`. The selected file replaces the default plugin list entirely, so start from a copy of the default before adding or removing entries. +- **Plugins under development are configured in `configs/app-config/app-config.local.yaml`** under `dynamicPlugins`, not in `dynamic-plugins.override.yaml`. Export them with `@red-hat-developer-hub/cli plugin export --dev --dynamic-plugins-root `; re-exporting and refreshing the browser is enough, no container restart. The Node.js debugger is already exposed on port 9229. +- **Both container tools are supported**: compose changes and documented instructions must work with Podman and Docker, and CI runs the matrix on both. Docs present the pair as TechDocs content tabs (`=== "Podman"` / `=== "Docker"`). +- **Images and behavior are tuned through environment variables**: pin `RHDH_IMAGE`, `CATALOG_INDEX_IMAGE`, `LIGHTSPEED_CORE_IMAGE`, `WITH_POSTGRES`, and similar in `.env`/`default.env` instead of editing `compose*.yaml`. +- **Baseline plugins**: `tests/required-plugins.yaml` lists plugins that must load regardless of configuration; `tests/validate-loaded-plugins.sh` fails when one disappears. ## Architecture - +- `compose.yaml` is the only base file. Each capability is an overlay that has to be named alongside it: `compose-with-db.yaml` (PostgreSQL), `compose-with-corporate-proxy.yaml`, `compose-dynamic-plugins-root.yaml`, `orchestrator/compose.yaml`, `intelligent-assistant/compose-with-okp.yaml`. `make … OVERLAYS=…` always passes `-f compose.yaml` first. +- Startup is two-stage. `install-dynamic-plugins` runs `prepare-and-install-dynamic-plugins.sh` as root, selects the plugin config, and extracts plugins into the `dynamic-plugins-root` and `extensions-catalog` volumes. `rhdh` then runs `wait-for-plugins-and-start.sh` as uid 1001, blocks until the installer's lock file is gone, and execs the Backstage backend. +- Runtime config layering, last one wins: base `app-config.yaml` → generated `app-config.dynamic-plugins.yaml` → `generated/app-config.patched.yaml` → `configs/app-config/app-config.db.yaml` when `WITH_POSTGRES=true` → `configs/app-config/app-config.local.yaml`. The patched copy only rewrites the users catalog path; components are referenced directly by the base config. +- `configs/` is bind-mounted whole at `/opt/app-root/src/configs`; `generated/` is runtime output and git-ignored. `local-plugins/` holds local plugin artifacts and is git-ignored apart from its `.gitignore`, and `dynamic-plugins-root` is a named volume used as the plugin cache. +- Optional components live in self-contained directories: `orchestrator/` (compose file, configs, workflow examples, and a README that explains adding its plugins to the override file) and `intelligent-assistant/` (OKP overlay). +- `tests/` is not a unit-test suite: each script asserts against a running instance through guest auth and `/api/extensions/loaded-plugins`, and needs `yq`, `jq`, and `curl`. CI invokes the same scripts from `.github/actions/rhdh-local-compose-test/action.yaml`. +- Intelligent Assistant config in `configs/extra-files/lightspeed-stack*.yaml` and `rhdh-profile.py` is generated from upstream by `scripts/sync-lightspeed-configs.sh`, which a scheduled workflow runs; fix those files upstream rather than hand-editing them. ## PR Conventions @@ -52,8 +59,10 @@ CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run - Compose overlay: see `compose-with-corporate-proxy.yaml` for how to extend `compose.yaml` - Dynamic plugins config: see files in `configs/dynamic-plugins/` for plugin configuration patterns -- Orchestrator integration: see `orchestrator/compose.yaml` for adding services via overlay +- Orchestrator integration: see `orchestrator/compose.yaml` for adding services via overlay, and `orchestrator/README.md` for registering its plugins - Shell utility scripts: see `prepare-and-install-dynamic-plugins.sh` and `wait-for-plugins-and-start.sh` +- Plugin development walkthrough: `docs/rhdh-local-guide/plugins-guide.md` (export, debug, local overrides) and `docs/rhdh-local-guide/dynamic-plugins-management.md` (catalog index, Extensions UI) +- Day-to-day operations and troubleshooting: `docs/rhdh-local-guide/operating-rhdh-local.md` - Local overrides: copy values from `default.env` into `.env` (git-ignored) to pin images, tags, and feature flags instead of editing compose files - CI verification: see `.github/actions/rhdh-local-compose-test/action.yaml` and `tests/` - User-facing docs (rendered as TechDocs): see `docs/`, plus `README.md` for the quick commands From 1f3e566c83290e0a589600ba9201761d2d502516 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Fri, 6 Nov 2026 23:33:09 +0100 Subject: [PATCH 4/9] docs(agent-readiness): cover local plugin development in AGENTS.md The intro is now two sentences: what RHDH Local is for (running RHDH on the machine with Docker or Podman Compose, a fast inner loop for catalog entries, TechDocs, templates, app config, and dynamic plugin development), and what it is not (a supported product, for production, or for teams). An agent should not propose this setup for production. Then add a Plugin Development section summarising the TechDocs workflow: load an exported plugin from local-plugins or the dynamic-plugins-root volume, iterate on a frontend plugin with plugin export --dev plus a browser refresh, debug a backend plugin over port 9229, and start from a clean state since exports persist in a volume. Commands use make targets where one exists, so the section matches the rest of the file. Assisted-by: DeepSeek V4.1 Flash Signed-off-by: Armel Soro --- AGENTS.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a92d4c9a..2681e61a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # rhdh-local -Red Hat Developer Hub (RHDH) Local — a Docker/Podman Compose setup for running RHDH locally for development and testing. Not a substitute for production RHDH; intended for individual developer use on a laptop/desktop. +RHDH Local runs Red Hat Developer Hub on your machine with Docker or Podman Compose — a fast inner loop for catalog entries, TechDocs, templates, app config, and dynamic plugin development. It is a testing and development tool only: not a supported product, not for production, not suitable for teams. Everything below is available through the `Makefile`; run `make help` for the full list. Commands default to Podman — pass `TOOL=docker` for Docker. `make lint` runs both linters from pinned container images (`DCLINT_IMAGE`, `SHELLCHECK_IMAGE`), so no Node.js, npx, or host linter installation is required. @@ -33,7 +33,7 @@ CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run - **Docs are part of the product**: everything under `docs/` is rendered as TechDocs through `mkdocs.yaml`, so a new page also needs a `nav` entry. `docs/`, `mkdocs.yaml`, and `catalog-info.yaml` are mounted read-only and copied into a writable workdir at startup, so restart `rhdh` to preview edits. - **User configuration is never committed**: `.env`, `configs/**/*.override.yaml`, `configs/**/*.local.yaml`, and `compose.override.yaml` are git-ignored. Change the tracked `*.example.yaml` counterparts instead; CI's "user config" matrix copies them into place verbatim, so they must stay valid and self-contained. - **Dynamic plugin configuration replaces, it does not merge**: `configs/dynamic-plugins/dynamic-plugins.override.yaml` wins over the deprecated `configs/dynamic-plugins.yaml`, which wins over `configs/dynamic-plugins/dynamic-plugins.yaml`. The selected file replaces the default plugin list entirely, so start from a copy of the default before adding or removing entries. -- **Plugins under development are configured in `configs/app-config/app-config.local.yaml`** under `dynamicPlugins`, not in `dynamic-plugins.override.yaml`. Export them with `@red-hat-developer-hub/cli plugin export --dev --dynamic-plugins-root `; re-exporting and refreshing the browser is enough, no container restart. The Node.js debugger is already exposed on port 9229. +- **Plugins under development**: keep the plugin's `dynamicPlugins` entry in `configs/app-config/app-config.local.yaml`, not in `dynamic-plugins.override.yaml`. See [Plugin Development](#plugin-development) for the export, iteration, and debug loops. - **Both container tools are supported**: compose changes and documented instructions must work with Podman and Docker, and CI runs the matrix on both. Docs present the pair as TechDocs content tabs (`=== "Podman"` / `=== "Docker"`). - **Images and behavior are tuned through environment variables**: pin `RHDH_IMAGE`, `CATALOG_INDEX_IMAGE`, `LIGHTSPEED_CORE_IMAGE`, `WITH_POSTGRES`, and similar in `.env`/`default.env` instead of editing `compose*.yaml`. - **Baseline plugins**: `tests/required-plugins.yaml` lists plugins that must load regardless of configuration; `tests/validate-loaded-plugins.sh` fails when one disappears. @@ -48,6 +48,15 @@ CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run - `tests/` is not a unit-test suite: each script asserts against a running instance through guest auth and `/api/extensions/loaded-plugins`, and needs `yq`, `jq`, and `curl`. CI invokes the same scripts from `.github/actions/rhdh-local-compose-test/action.yaml`. - Intelligent Assistant config in `configs/extra-files/lightspeed-stack*.yaml` and `rhdh-profile.py` is generated from upstream by `scripts/sync-lightspeed-configs.sh`, which a scheduled workflow runs; fix those files upstream rather than hand-editing them. +## Plugin Development + +Plugin development is a first-class use case, not an afterthought: RHDH Local loads dynamic plugins at boot, so a rebuilt plugin runs in a real RHDH UI and backend without publishing to a registry or deploying to a cluster. The full walkthrough is `docs/rhdh-local-guide/plugins-guide.md`; the short version: + +- **Load an exported plugin**: put the package in `local-plugins/` (mounted at `/opt/app-root/src/local-plugins` and loaded without downloading) or copy `dist-dynamic` into the `dynamic-plugins-root` volume, then reference it from the plugin config. Files must be readable by the container — `chmod -R 777 local-plugins` for quick tests. +- **Frontend iteration**: `npx @red-hat-developer-hub/cli@latest plugin export --dev --dynamic-plugins-root /dynamic-plugins-root`, start with `make start OVERLAYS=dynamic-plugins-root`, and keep the plugin's `dynamicPlugins` entry in `configs/app-config/app-config.local.yaml`. After a code change, re-run the export and refresh the browser — no container restart. +- **Backend debugging**: copy `dist-dynamic` into the running container (`podman cp dist-dynamic rhdh:/opt/app-root/src/dynamic-plugins-root/`), `make restart`, and attach a Node debugger to port 9229 with `remoteRoot` at that in-container path and `localRoot` at the plugin source. Repeat copy + restart after each rebuild. +- **Start clean** before a frontend iteration — `make clean` (`down --volumes`) — because exported plugins persist in the `dynamic-plugins-root` volume. + ## PR Conventions - Conventional Commits are used: `fix:`, `feat:`, `chore:`, `ci:`, `docs:`, etc. From cb70b557b8a458be5b79398570da620015b96119 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 7 Nov 2026 00:03:22 +0100 Subject: [PATCH 5/9] feat(make): add targets to inspect the running setup and reset it Stopping, starting, and linting were covered, but everything needed to look at what is actually running meant dropping to raw compose commands. Add `logs` (all services, or SERVICE=rhdh for one), `ps -a` so the short-lived installer container is visible after it exits, `list-services` to see what a set of overlays contributes, and `effective-compose` to render the merged config. The latter interpolates .env, so its output can contain secrets and must not be pasted into a PR. Add `reset` for a full teardown: containers, volumes, and every pulled image. Compose's --rmi all only covers service images, so the dclint and shellcheck images used by `make lint` are removed explicitly, with a leading `-` so a missing image does not fail a cleanup run. Each target goes through $(COMPOSE), so TOOL and OVERLAYS apply consistently; `logs` uses a SERVICE override because a bare argument would be read as another make target. Assisted-by: DeepSeek V4.1 Flash Signed-off-by: Armel Soro --- Makefile | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8570702f..b4177fda 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,11 @@ # e.g. make start OVERLAYS="db orchestrator" # DCLINT_IMAGE dclint image used by `make lint`, pinned to a release tag # SHELLCHECK_IMAGE shellcheck image used by `make lint`, pinned to a release tag +# SERVICE service to act on for `make logs`, default all services # TOOL ?= podman OVERLAYS ?= +SERVICE ?= # Named overlays, so nobody has to remember compose file names. OVERLAY_NAMES := db corporate-proxy dynamic-plugins-root orchestrator @@ -32,7 +34,7 @@ DCLINT_IMAGE ?= docker.io/zavoloklom/dclint:3.1.0 SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0 LINT_MOUNT := -v "$(CURDIR)":/app:ro,z -w /app -.PHONY: help start stop restart plugins-install down clean lint +.PHONY: help start stop restart logs ps list-services effective-compose plugins-install down clean reset lint .DEFAULT_GOAL := help @@ -41,6 +43,7 @@ help: ## Show this help | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-17s\033[0m %s\n", $$1, $$2}' @printf '\n OVERLAYS: %s (or a path to any compose file)\n' "$(OVERLAY_NAMES)" @printf ' e.g. make start OVERLAYS="db orchestrator"\n' + @printf ' e.g. make logs SERVICE=rhdh\n' start: ## Start RHDH Local $(COMPOSE) up -d @@ -52,6 +55,18 @@ restart: ## Restart RHDH only, for configuration changes $(COMPOSE) stop rhdh $(COMPOSE) start rhdh +logs: ## Follow logs for all services, or SERVICE=rhdh for one + $(COMPOSE) logs -f $(SERVICE) + +ps: ## Show all containers, including stopped ones + $(COMPOSE) ps -a + +list-services: ## List the services defined by the compose files + $(COMPOSE) config --services + +effective-compose: ## Render the effective Compose config + $(COMPOSE) config + plugins-install: ## Reinstall dynamic plugins, then restart RHDH $(COMPOSE) run install-dynamic-plugins $(COMPOSE) stop rhdh @@ -63,6 +78,10 @@ down: ## Stop and remove all containers and the network, keeping volumes clean: ## Stop everything and remove volumes $(COMPOSE) down --volumes +reset: ## Remove containers, volumes, and every pulled image + $(COMPOSE) down --volumes --rmi all + -$(TOOL) rmi $(DCLINT_IMAGE) $(SHELLCHECK_IMAGE) 2>/dev/null + lint: ## Lint the tracked compose files and shell scripts $(TOOL) run --rm $(LINT_MOUNT) $(DCLINT_IMAGE) \ $(shell git ls-files 'compose*.yaml' 'orchestrator/compose*.yaml') From faeedea1733b776f8f4c75c2ebe3eb82e6003165 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 7 Nov 2026 00:03:27 +0100 Subject: [PATCH 6/9] docs(agent-readiness): document the new make targets and the PR template Cover the inspection and teardown targets so an agent reaches for them instead of raw compose commands, and note that `effective-compose` output can contain secrets because it interpolates .env. Replace the raw `podman compose -f ... config` example in Verification with `make effective-compose OVERLAYS=db`, which is both shorter and guaranteed to name compose.yaml explicitly. Also require PR descriptions to follow .github/PULL_REQUEST_TEMPLATE.md. The template matters for agents that open PRs with gh, which sends the body verbatim and therefore skips the template the web UI would prefill. Assisted-by: DeepSeek V4.1 Flash Signed-off-by: Armel Soro --- AGENTS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2681e61a..c6c5b425 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,9 +9,12 @@ Everything below is available through the `Makefile`; run `make help` for the fu - Start: `make start` (`podman compose up -d`) - Stop RHDH only: `make stop` (`podman compose stop rhdh`) - Restart RHDH only, for configuration changes: `make restart` +- Follow logs for all services, or one: `make logs` / `make logs SERVICE=rhdh` +- Inspect the setup: `make ps` (all containers, stopped included), `make list-services` (service names), `make effective-compose` (merged config) - Reinstall plugins, then restart RHDH: `make plugins-install` - Stop and remove all containers: `make down` - Teardown including volumes: `make clean` +- Full reset, including every pulled image (runtime and lint, they download again on next use): `make reset` - Compose overlays: `make start OVERLAYS="db orchestrator"` — space-separated names, applied on top of `compose.yaml`, which the Makefile then names explicitly. Available names: `db`, `corporate-proxy`, `dynamic-plugins-root`, `orchestrator`; any `*.yaml` path also works for personal overrides. A local `compose.override.yaml` only applies when `OVERLAYS` is empty. - Lint tracked compose files and shell scripts: `make lint` @@ -19,7 +22,7 @@ Everything below is available through the `Makefile`; run `make help` for the fu CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run whichever covers what you changed. All of the lint checks need only the container engine; the runtime validators need RHDH running plus `yq`, `jq`, and `curl`. -- Compose change: render the config for the overlay you touched, e.g. `podman compose -f compose.yaml -f compose-with-db.yaml config` +- Compose change: render the config for the overlay you touched, e.g. `make effective-compose OVERLAYS=db` (or `make list-services OVERLAYS=db` to check which services it adds). Because it interpolates `.env`, `make effective-compose` output can contain secrets — never paste it into a PR or issue. - Dynamic plugins actually load (RHDH must be running; needs `yq`, `jq`, `curl`): `./tests/validate-loaded-plugins.sh` - Intelligent Assistant: `./tests/validate-intelligent-assistant-compose.sh` and `./tests/validate-intelligent-assistant-runtime.sh` - Single compose file: `podman run --rm -v "$PWD":/app:ro,z -w /app docker.io/zavoloklom/dclint:3.1.0 `, using the same image as `make lint` @@ -62,6 +65,7 @@ Plugin development is a first-class use case, not an afterthought: RHDH Local lo - Conventional Commits are used: `fix:`, `feat:`, `chore:`, `ci:`, `docs:`, etc. - Scope examples: `nightly`, `deps`, `lightspeed`, `plugins` - Agent-assisted commits should include an `Assisted-by: ` footer +- **Always follow the PR template**: `.github/PULL_REQUEST_TEMPLATE.md` — keep all of its sections (description, related issue, acceptance criteria checklist, how to test) and either tick each checklist item or say why it does not apply. GitHub prefills it in the web UI, but a `gh pr create` body has to reproduce it. - Report issues to Jira project RHIDP with Component: **RHDH Local** ## Pattern References From 2e4a1262c3fdcfa0ebe30af88616d0a3c57f38d7 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Mon, 9 Nov 2026 17:32:53 +0100 Subject: [PATCH 7/9] docs(agent-readiness): trim AGENTS.md to non-discoverable guidance Remove commands, filenames, and pattern references that an agent can derive from `make help`, directory listings, and file contents. Keep only judgment calls, gotchas, and constraints that would cause mistakes without explicit documentation: branching strategy, config replacement semantics, overlay consistency, CI path filtering, example files as test inputs, and shell script conventions. Assisted-by: Claude --- AGENTS.md | 95 +++++++++++++++++-------------------------------------- 1 file changed, 29 insertions(+), 66 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c6c5b425..51f0c8db 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,80 +2,43 @@ RHDH Local runs Red Hat Developer Hub on your machine with Docker or Podman Compose — a fast inner loop for catalog entries, TechDocs, templates, app config, and dynamic plugin development. It is a testing and development tool only: not a supported product, not for production, not suitable for teams. -Everything below is available through the `Makefile`; run `make help` for the full list. Commands default to Podman — pass `TOOL=docker` for Docker. `make lint` runs both linters from pinned container images (`DCLINT_IMAGE`, `SHELLCHECK_IMAGE`), so no Node.js, npx, or host linter installation is required. +Run `make help` for the full list of targets. Commands default to Podman — pass `TOOL=docker` for Docker. -## Build & Test Commands +## Key conventions -- Start: `make start` (`podman compose up -d`) -- Stop RHDH only: `make stop` (`podman compose stop rhdh`) -- Restart RHDH only, for configuration changes: `make restart` -- Follow logs for all services, or one: `make logs` / `make logs SERVICE=rhdh` -- Inspect the setup: `make ps` (all containers, stopped included), `make list-services` (service names), `make effective-compose` (merged config) -- Reinstall plugins, then restart RHDH: `make plugins-install` -- Stop and remove all containers: `make down` -- Teardown including volumes: `make clean` -- Full reset, including every pulled image (runtime and lint, they download again on next use): `make reset` -- Compose overlays: `make start OVERLAYS="db orchestrator"` — space-separated names, applied on top of `compose.yaml`, which the Makefile then names explicitly. Available names: `db`, `corporate-proxy`, `dynamic-plugins-root`, `orchestrator`; any `*.yaml` path also works for personal overrides. A local `compose.override.yaml` only applies when `OVERLAYS` is empty. -- Lint tracked compose files and shell scripts: `make lint` - -## Verification - -CI runs these through `.github/actions/rhdh-local-compose-test/action.yaml`; run whichever covers what you changed. All of the lint checks need only the container engine; the runtime validators need RHDH running plus `yq`, `jq`, and `curl`. - -- Compose change: render the config for the overlay you touched, e.g. `make effective-compose OVERLAYS=db` (or `make list-services OVERLAYS=db` to check which services it adds). Because it interpolates `.env`, `make effective-compose` output can contain secrets — never paste it into a PR or issue. -- Dynamic plugins actually load (RHDH must be running; needs `yq`, `jq`, `curl`): `./tests/validate-loaded-plugins.sh` -- Intelligent Assistant: `./tests/validate-intelligent-assistant-compose.sh` and `./tests/validate-intelligent-assistant-runtime.sh` -- Single compose file: `podman run --rm -v "$PWD":/app:ro,z -w /app docker.io/zavoloklom/dclint:3.1.0 `, using the same image as `make lint` -- Single shell script: `podman run --rm -v "$PWD":/app:ro,z -w /app docker.io/koalaman/shellcheck:v0.11.0 `, using the same image as `make lint` - -`make lint` and repo-wide dclint only cover git-tracked files. Developer-specific `*.local.yaml` overrides are deliberately not linted, so lint findings never point at files that are not in the repository. - -## Key Conventions - -- **Branching**: `main` is the latest stable GA release, `dev` carries development for the next release, `release-x.y` stabilizes a release and takes its patch fixes. Target `dev` for features, docs, and dependency updates; `release-x.y` for bug fixes on a supported release; do not target `main`, which maintainers update by merge and cherry-pick. `.github/workflows/branch-target-check.yaml` comments a warning on every PR opened against `main`. -- **Docs are part of the product**: everything under `docs/` is rendered as TechDocs through `mkdocs.yaml`, so a new page also needs a `nav` entry. `docs/`, `mkdocs.yaml`, and `catalog-info.yaml` are mounted read-only and copied into a writable workdir at startup, so restart `rhdh` to preview edits. -- **User configuration is never committed**: `.env`, `configs/**/*.override.yaml`, `configs/**/*.local.yaml`, and `compose.override.yaml` are git-ignored. Change the tracked `*.example.yaml` counterparts instead; CI's "user config" matrix copies them into place verbatim, so they must stay valid and self-contained. -- **Dynamic plugin configuration replaces, it does not merge**: `configs/dynamic-plugins/dynamic-plugins.override.yaml` wins over the deprecated `configs/dynamic-plugins.yaml`, which wins over `configs/dynamic-plugins/dynamic-plugins.yaml`. The selected file replaces the default plugin list entirely, so start from a copy of the default before adding or removing entries. -- **Plugins under development**: keep the plugin's `dynamicPlugins` entry in `configs/app-config/app-config.local.yaml`, not in `dynamic-plugins.override.yaml`. See [Plugin Development](#plugin-development) for the export, iteration, and debug loops. +- **Branching**: target `dev` for features, docs, and dependency updates; `release-x.y` for bug fixes on a supported release. Do not target `main` — maintainers update it by merge and cherry-pick. - **Both container tools are supported**: compose changes and documented instructions must work with Podman and Docker, and CI runs the matrix on both. Docs present the pair as TechDocs content tabs (`=== "Podman"` / `=== "Docker"`). -- **Images and behavior are tuned through environment variables**: pin `RHDH_IMAGE`, `CATALOG_INDEX_IMAGE`, `LIGHTSPEED_CORE_IMAGE`, `WITH_POSTGRES`, and similar in `.env`/`default.env` instead of editing `compose*.yaml`. -- **Baseline plugins**: `tests/required-plugins.yaml` lists plugins that must load regardless of configuration; `tests/validate-loaded-plugins.sh` fails when one disappears. +- **Docs are part of the product**: everything under `docs/` is rendered as TechDocs through `mkdocs.yaml`, so a new page also needs a `nav` entry. Restart `rhdh` to preview edits (the mount is read-only, copied into a writable workdir at startup). +- **User configuration is never committed**: `.env`, `configs/**/*.override.yaml`, `configs/**/*.local.yaml`, and `compose.override.yaml` are git-ignored. Change the tracked `*.example.yaml` counterparts instead. +- **`*.example.yaml` files are CI test inputs**: CI copies them verbatim into the corresponding override/local files, so they must parse and work standalone — treat them as code, not documentation. +- **Images and behavior are tuned through environment variables** in `.env`/`default.env`, not by editing compose files. +- **`make effective-compose` output can contain secrets** (it interpolates `.env`) — never paste it into a PR or issue. +- **Lint only covers git-tracked files**. Developer-specific `*.local.yaml` overrides are deliberately excluded. +- **Shell scripts use `set -euo pipefail`** and are checked by ShellCheck in CI — new scripts must follow the same pattern. +- **CI is path-filtered**: lint and test jobs skip when no relevant files changed. If you add a new file type or top-level path, check whether the changed-files filter in the CI workflow covers it — "CI passed" may mean "CI didn't run." ## Architecture -- `compose.yaml` is the only base file. Each capability is an overlay that has to be named alongside it: `compose-with-db.yaml` (PostgreSQL), `compose-with-corporate-proxy.yaml`, `compose-dynamic-plugins-root.yaml`, `orchestrator/compose.yaml`, `intelligent-assistant/compose-with-okp.yaml`. `make … OVERLAYS=…` always passes `-f compose.yaml` first. -- Startup is two-stage. `install-dynamic-plugins` runs `prepare-and-install-dynamic-plugins.sh` as root, selects the plugin config, and extracts plugins into the `dynamic-plugins-root` and `extensions-catalog` volumes. `rhdh` then runs `wait-for-plugins-and-start.sh` as uid 1001, blocks until the installer's lock file is gone, and execs the Backstage backend. -- Runtime config layering, last one wins: base `app-config.yaml` → generated `app-config.dynamic-plugins.yaml` → `generated/app-config.patched.yaml` → `configs/app-config/app-config.db.yaml` when `WITH_POSTGRES=true` → `configs/app-config/app-config.local.yaml`. The patched copy only rewrites the users catalog path; components are referenced directly by the base config. -- `configs/` is bind-mounted whole at `/opt/app-root/src/configs`; `generated/` is runtime output and git-ignored. `local-plugins/` holds local plugin artifacts and is git-ignored apart from its `.gitignore`, and `dynamic-plugins-root` is a named volume used as the plugin cache. -- Optional components live in self-contained directories: `orchestrator/` (compose file, configs, workflow examples, and a README that explains adding its plugins to the override file) and `intelligent-assistant/` (OKP overlay). -- `tests/` is not a unit-test suite: each script asserts against a running instance through guest auth and `/api/extensions/loaded-plugins`, and needs `yq`, `jq`, and `curl`. CI invokes the same scripts from `.github/actions/rhdh-local-compose-test/action.yaml`. -- Intelligent Assistant config in `configs/extra-files/lightspeed-stack*.yaml` and `rhdh-profile.py` is generated from upstream by `scripts/sync-lightspeed-configs.sh`, which a scheduled workflow runs; fix those files upstream rather than hand-editing them. - -## Plugin Development - -Plugin development is a first-class use case, not an afterthought: RHDH Local loads dynamic plugins at boot, so a rebuilt plugin runs in a real RHDH UI and backend without publishing to a registry or deploying to a cluster. The full walkthrough is `docs/rhdh-local-guide/plugins-guide.md`; the short version: +- **Overlay model**: `compose.yaml` is the only base file. Every overlay must be named alongside it — `make … OVERLAYS=…` always passes `-f compose.yaml` first. A local `compose.override.yaml` only applies when `OVERLAYS` is empty. +- **`OVERLAYS` must be consistent across commands**: if you start with `make start OVERLAYS="db orchestrator"`, pass the same `OVERLAYS` to `stop`, `restart`, `logs`, `effective-compose`, `list-services`, and any other target — otherwise the command operates on the base config only and ignores the overlay services. +- **Two-stage startup**: the `install-dynamic-plugins` service runs as root, selects the plugin config, and extracts plugins into the `dynamic-plugins-root` and `extensions-catalog` volumes. The `rhdh` service then blocks until the installer's lock file is gone and execs the Backstage backend as uid 1001. +- **Config layering** (last wins): `app-config.yaml` → `app-config.dynamic-plugins.yaml` → `generated/app-config.patched.yaml` → `app-config.db.yaml` (when `WITH_POSTGRES=true`) → `app-config.local.yaml`. +- **Dynamic plugin configuration replaces, it does not merge**: the selected plugin config file replaces the default plugin list entirely, so start from a copy of the default before adding or removing entries. +- **Orchestrator plugins are a separate step from the overlay**: `make start OVERLAYS=orchestrator` only adds the compose services — the orchestrator's dynamic plugins must be appended to the override file separately (see `orchestrator/README.md`). +- **Tests need a running instance**: scripts in `tests/` assert against a live RHDH through guest auth, not unit tests. They need `yq`, `jq`, and `curl`. +- **Lightspeed configs are generated from upstream** by a scheduled workflow — fix those files upstream rather than hand-editing them. -- **Load an exported plugin**: put the package in `local-plugins/` (mounted at `/opt/app-root/src/local-plugins` and loaded without downloading) or copy `dist-dynamic` into the `dynamic-plugins-root` volume, then reference it from the plugin config. Files must be readable by the container — `chmod -R 777 local-plugins` for quick tests. -- **Frontend iteration**: `npx @red-hat-developer-hub/cli@latest plugin export --dev --dynamic-plugins-root /dynamic-plugins-root`, start with `make start OVERLAYS=dynamic-plugins-root`, and keep the plugin's `dynamicPlugins` entry in `configs/app-config/app-config.local.yaml`. After a code change, re-run the export and refresh the browser — no container restart. -- **Backend debugging**: copy `dist-dynamic` into the running container (`podman cp dist-dynamic rhdh:/opt/app-root/src/dynamic-plugins-root/`), `make restart`, and attach a Node debugger to port 9229 with `remoteRoot` at that in-container path and `localRoot` at the plugin source. Repeat copy + restart after each rebuild. -- **Start clean** before a frontend iteration — `make clean` (`down --volumes`) — because exported plugins persist in the `dynamic-plugins-root` volume. +## Plugin development -## PR Conventions +Plugin development is a first-class use case. RHDH Local loads dynamic plugins at boot, so a rebuilt plugin runs in a real RHDH UI and backend without publishing to a registry. The full walkthrough is in `docs/rhdh-local-guide/plugins-guide.md`; the key constraints: -- Conventional Commits are used: `fix:`, `feat:`, `chore:`, `ci:`, `docs:`, etc. -- Scope examples: `nightly`, `deps`, `lightspeed`, `plugins` -- Agent-assisted commits should include an `Assisted-by: ` footer -- **Always follow the PR template**: `.github/PULL_REQUEST_TEMPLATE.md` — keep all of its sections (description, related issue, acceptance criteria checklist, how to test) and either tick each checklist item or say why it does not apply. GitHub prefills it in the web UI, but a `gh pr create` body has to reproduce it. -- Report issues to Jira project RHIDP with Component: **RHDH Local** +- Keep the plugin's `dynamicPlugins` entry in `configs/app-config/app-config.local.yaml`, not in the dynamic plugins override file. +- Files in `local-plugins/` must be readable by the container (uid 1001). +- Exported plugins persist in the `dynamic-plugins-root` volume — run `make clean` before a fresh frontend iteration. -## Pattern References +## PR conventions -- Compose overlay: see `compose-with-corporate-proxy.yaml` for how to extend `compose.yaml` -- Dynamic plugins config: see files in `configs/dynamic-plugins/` for plugin configuration patterns -- Orchestrator integration: see `orchestrator/compose.yaml` for adding services via overlay, and `orchestrator/README.md` for registering its plugins -- Shell utility scripts: see `prepare-and-install-dynamic-plugins.sh` and `wait-for-plugins-and-start.sh` -- Plugin development walkthrough: `docs/rhdh-local-guide/plugins-guide.md` (export, debug, local overrides) and `docs/rhdh-local-guide/dynamic-plugins-management.md` (catalog index, Extensions UI) -- Day-to-day operations and troubleshooting: `docs/rhdh-local-guide/operating-rhdh-local.md` -- Local overrides: copy values from `default.env` into `.env` (git-ignored) to pin images, tags, and feature flags instead of editing compose files -- CI verification: see `.github/actions/rhdh-local-compose-test/action.yaml` and `tests/` -- User-facing docs (rendered as TechDocs): see `docs/`, plus `README.md` for the quick commands +- Conventional Commits: `fix:`, `feat:`, `chore:`, `ci:`, `docs:`, etc. +- Agent-assisted commits include an `Assisted-by: ` footer. +- Always follow the PR template in `.github/PULL_REQUEST_TEMPLATE.md` — keep all sections and either tick each checklist item or say why it does not apply. +- Report issues to Jira project RHIDP with Component: **RHDH Local**. From f21c7c2037e5264dd616e23793de72cd9b06fd79 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Mon, 9 Nov 2026 17:37:18 +0100 Subject: [PATCH 8/9] docs(agent-readiness): restore startup script names in AGENTS.md The script names make the two-stage startup description actionable rather than abstract, and are stable enough to be worth naming. Assisted-by: Claude --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 51f0c8db..91b80d09 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ Run `make help` for the full list of targets. Commands default to Podman — pas - **Overlay model**: `compose.yaml` is the only base file. Every overlay must be named alongside it — `make … OVERLAYS=…` always passes `-f compose.yaml` first. A local `compose.override.yaml` only applies when `OVERLAYS` is empty. - **`OVERLAYS` must be consistent across commands**: if you start with `make start OVERLAYS="db orchestrator"`, pass the same `OVERLAYS` to `stop`, `restart`, `logs`, `effective-compose`, `list-services`, and any other target — otherwise the command operates on the base config only and ignores the overlay services. -- **Two-stage startup**: the `install-dynamic-plugins` service runs as root, selects the plugin config, and extracts plugins into the `dynamic-plugins-root` and `extensions-catalog` volumes. The `rhdh` service then blocks until the installer's lock file is gone and execs the Backstage backend as uid 1001. +- **Two-stage startup**: `install-dynamic-plugins` runs `prepare-and-install-dynamic-plugins.sh` as root, selects the plugin config, and extracts plugins into the `dynamic-plugins-root` and `extensions-catalog` volumes. `rhdh` then runs `wait-for-plugins-and-start.sh` as uid 1001, blocks until the installer's lock file is gone, and execs the Backstage backend. - **Config layering** (last wins): `app-config.yaml` → `app-config.dynamic-plugins.yaml` → `generated/app-config.patched.yaml` → `app-config.db.yaml` (when `WITH_POSTGRES=true`) → `app-config.local.yaml`. - **Dynamic plugin configuration replaces, it does not merge**: the selected plugin config file replaces the default plugin list entirely, so start from a copy of the default before adding or removing entries. - **Orchestrator plugins are a separate step from the overlay**: `make start OVERLAYS=orchestrator` only adds the compose services — the orchestrator's dynamic plugins must be appended to the override file separately (see `orchestrator/README.md`). From 5de623e2dda1982775209e123c1a206c3fe622be Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Mon, 9 Nov 2026 17:50:32 +0100 Subject: [PATCH 9/9] chore(agent-readiness): add Claude Code lint hooks for YAML and shell files PostToolUse hook runs dclint on compose files and shellcheck on shell scripts after every edit, matching what rhdh-cli does for prettier. Assisted-by: Claude --- .claude/settings.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..8e44fb02 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit|Write", + "hooks": [ + { + "type": "command", + "command": "FILE=\"$CLAUDE_FILE_PATH\"; case \"$FILE\" in *.yaml|*.yml) npx --yes dclint \"$FILE\" 2>/dev/null || true ;; *.sh) shellcheck \"$FILE\" 2>/dev/null || true ;; esac" + } + ] + } + ] + } +}