deployment-remediation
Skill1 starsChanged 47 days agoApache-2.0View on GitHub
Deployment-config remediation patterns for services /otel-instrument cannot bootstrap (generatorSupported:false, inScope:true — a third-party binary/image with no owned application source, but real native OTel support). Use when generating a deployment-config diff via /otel-remediate.
In this repository18 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- otel-backendSkill
- otel-business-attrsSkill
- otel-collectorSkill
- otel-evaluateSkill
- otel-initSkill
- otel-instrumentSkill
- otel-remediateSkill
- otel-uninstrumentSkill
- semconv-disciplineSkill
- new-backendSkill
- validate-pluginSkill
- business-attr-uxSkill
- collector-topologySkill
- language-maturitySkill
- semconv-disciplineSkill
- terraform-patternsSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 43
Verify current values against Keycloak's own docs before generating …
- Very specific: line 106
Add transform/keycloak-scrub to the traces pipeline between transform and batch (memory_limiter stays first).
- Very specific: line 156
Always show a unified diff (--- a/<path> / +++ b/<path>, @@ hunk headers) against the actual file content you read, never a bare "add these …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Deployment-Config Remediation
Who this is for
generatorSupported: false, inScope: true is a real, common category, not an edge case: an
upstream binary or container image (Keycloak, nginx, Envoy, a managed database/queue image, a
Helm-installed operator) with no application source in the repo for /otel-instrument to
bootstrap, but a genuine deployed workload with its own native OpenTelemetry (or OTel-adjacent)
configuration surface — usually environment variables or CLI flags read at container start.
/otel-evaluate's brownfield-auditor already audits these services well: it reads
service.deployment.configFiles (the Kubernetes manifest, Dockerfile, docker-compose file, Helm
values) the same way it does for any other service, and reports missing/misconfigured native OTel
settings as ordinary findings (mostly CF — telemetry configuration). What was missing is a way
to turn those findings into a concrete diff, the same way /otel-instrument --fix <ids> does for
a generatorSupported: true service's source files. This skill is that missing half, dispatched
by /otel-remediate.
v1 scope: Keycloak only
Only Keycloak is supported in v1. This list is deliberately a table, not prose, so adding a
second target later is an addition, not a rewrite — but do not guess at an unlisted target's
config surface by analogy; every binary's flags are different, and a wrong guess here writes
config that doesn't do what it claims. For anything not in the table below, /otel-remediate
must refuse by name by name, the same "wrong code is worse than no code" principle
instrumentation-gen already applies to an unsupported language/runtime — do NOT emit a diff for
a target this skill doesn't cover.
| Target | Detection signal | inScope shape |
| Keycloak | A container image reference matching quay.io/keycloak/keycloak, keycloak/keycloak, or the older jboss/keycloak, in a Dockerfile FROM, a Kubernetes/Helm manifest's image: field, a docker-compose image: field, or a Terraform helm_release/kubernetes_manifest resource's chart/embedded values/image field (#176) — same target, just provisioned from .tf instead of a raw manifest; the scanner notes which source it came from | host: kubernetes / container / standalone, generatorSupported: false |
Keycloak: native OTel configuration surface
Keycloak is Quarkus-based; its runtime config properties (kebab-case, e.g. tracing-enabled) map
to environment variables by Quarkus's standard convention: uppercase, - → _, prefixed KC_.
Verify current values against Keycloak's own docs before generating
(https://github.com/keycloak/keycloak/blob/main/docs/guides/observability/tracing.adoc,
https://www.keycloak.org/server/logging) — Keycloak's own config surface has already renamed
properties within its lifecycle (see the deprecation note below), so treat this table as
"verified as of this writing," not permanently pinned.
All three signals share one endpoint. --telemetry-endpoint / KC_TELEMETRY_ENDPOINT is
"available only when any of available OpenTelemetry components (Logs, Metrics, Traces) is turned
on," and --tracing-endpoint "is inherited from the telemetry-endpoint option" when not given
(confirmed against Keycloak's own docs, quay.io/keycloak/keycloak:26.7.0 start --help-all,
#196). Propose KC_TELEMETRY_ENDPOINT, not KC_TRACING_ENDPOINT, as the endpoint variable —
setting only KC_TRACING_ENDPOINT means enabling OTLP logs or metrics later silently falls back
to localhost:4317 a second time, unset. Only propose KC_TRACING_ENDPOINT directly when traces
genuinely need to go somewhere DIFFERENT from logs/metrics, a real but unusual case — say so
explicitly when you do.
Tracing (default OTLP protocol is gRPC, default endpoint http://localhost:4317 — same
default this plugin uses elsewhere, so a target already running a collector on the plugin's
standard port needs no endpoint override):
| Env var | Purpose | Notes |
KC_TRACING_ENABLED=true | Turns tracing on. Build-time option (tracing-enabled) | Tracing is gated behind the opentelemetry feature, which is enabled by default in current Keycloak — do not also propose a --features=opentelemetry flag unless the target is confirmed on an older version where it wasn't. |
KC_TELEMETRY_ENDPOINT | Shared OTLP endpoint for traces, logs and metrics | See "All three signals share one endpoint" above. Maps to quarkus.otel.exporter.otlp.endpoint. Omit if the deployment already exports elsewhere and only the endpoint is unset — do not invent a value; ask/flag it as <confirm your collector endpoint> the same way instrumentation-gen never invents a Terraform-owned identifier. |
KC_TELEMETRY_SERVICE_NAME | The service.name resource attribute | Use this, not KC_TRACING_SERVICE_NAME — Keycloak's own docs mark tracing-service-name deprecated in favor of telemetry-service-name. Default is literally keycloak; every Keycloak deployment in a multi-service repo needs this set explicitly or every one of them reports the identical service.name. |
KC_TELEMETRY_RESOURCE_ATTRIBUTES | Extra resource attributes (k8s.namespace.name, etc.) | Same deprecation as above (was tracing-resource-attributes). The Keycloak Operator sets this automatically when present — if the target uses the Operator, do not propose it as missing without checking whether the Operator already injects it. |
KC_TRACING_SAMPLER_TYPE / KC_TRACING_SAMPLER_RATIO | Sampler type/ratio | Default sampler traceidratio, default ratio 1.0 (all traces sampled). Do not put a sampling change in the diff as if it were a gap, but do not stay silent about volume either: raise it as a choice for the user (see "Tracing exports credentials" below). |
Tracing exports credentials: scrub before enabling (#197)
Keycloak's HTTP server spans record url.query verbatim, and Keycloak puts live credentials in
query strings. The semantic conventions make url.query Conditionally Required on HTTP server
spans and only say that sensitive content "SHOULD be scrubbed when instrumentations can identify
it" (checked against semantic-conventions v1.44.0, docs/http/http-spans.md); an instrumentation
cannot identify an application's own credential keys, and Keycloak's are not on the spec's default
redaction list. Reported and reproduced in #197 with quay.io/keycloak/keycloak:26.7.0 exporting
to otelcol-contrib 0.164.0:
| Where | Query string carries | Holding it allows |
/realms/<r>/login-actions/action-token | key=<token> | acting on the account: it is the reset-password / verify-email credential |
/realms/<r>/protocol/openid-connect/auth and redirects | code=…, session_state=…, state=… | replaying an OIDC authorization code |
So applying KC_TRACING_ENABLED=true as proposed puts replayable credentials into the trace
backend, readable by everyone with trace access. Treat the scrub as a precondition of the diff,
not an optional extra:
- It must be live on the receiving Collector before tracing is switched on. If that Collector is owned elsewhere (another team, a managed gateway), the env-var diff must not be applied until it is. Say this in the report; do not leave it implied.
- The scrub, scoped to this service by its
service.nameso other services' query strings are untouched (checked againstotelcol-contrib0.164.0: this service's spans lose both attributes, other services' keep them):
Addprocessors: transform/keycloak-scrub: error_mode: ignore trace_statements: - context: span statements: - delete_key(attributes, "url.query") where resource.attributes["service.name"] == "<service.name>" - delete_key(attributes, "url.full") where resource.attributes["service.name"] == "<service.name>"transform/keycloak-scrubto thetracespipeline betweentransformandbatch(memory_limiterstays first). Prefer deleting over redacting by key (key=,code=,session_state=): a deny-list of keys misses the next one Keycloak adds, and the path already says what the request was. - Already enabled? Then the exposure is current, not hypothetical. Lead the report with it even when nothing else needs proposing.
- Volume is a choice, not a silent default. The reporter measured about 1,500 spans in two
minutes on an idle dev instance at the default ratio of
1.0, most of them internal and database spans. OfferKC_TRACING_SAMPLER_RATIO(or tail sampling at a gateway) as a decision for the user, and do not add it to the diff.
Logging — Keycloak's console handler logs unstructured plain text by default:
| Env var | Purpose | Notes |
KC_LOG_CONSOLE_OUTPUT=json | Structured JSON console logs | Also supports ecs (Elastic Common Schema) instead of the default JSON shape — propose plain json unless the target's existing log pipeline is confirmed ECS-shaped. |
Metrics — KC_METRICS_ENABLED=true (build-time metrics-enabled) is the on/off switch;
if already true, that is not a finding — do not propose re-adding it.
Native OTLP logs/metrics (Preview, #196) — Keycloak 26 can ALSO export logs and metrics
directly over OTLP, not just to stdout/Prometheus. Neither is a finding when the target already
has KC_LOG_CONSOLE_OUTPUT=json and/or KC_METRICS_ENABLED=true — those are a defensible,
already-working setup — but mention the OTLP path exists as an option next to them, not silently:
it gives logs/metrics the same service.name / resource attributes as traces, which a stdout
tail or a Prometheus scrape does not carry. Only propose actually ADDING these if the target has
NEITHER the existing path NOR the OTLP path for that signal.
| Env var | Purpose | Notes |
KC_TELEMETRY_LOGS_ENABLED=true | Export logs over OTLP | Requires the opentelemetry-logs feature, which is Preview, not enabled by default — also propose --features=opentelemetry-logs (a build-time flag, not an env var: it belongs in the image's entrypoint args or a FROM-stage build arg, not the env: block — say so, don't just add it to the env-var diff). Confirmed via Keycloak's own --help-all: "Available only when feature 'opentelemetry-logs:v1' is enabled." |
KC_TELEMETRY_METRICS_ENABLED=true | Export metrics over OTLP | Requires BOTH the opentelemetry-metrics feature flag (Preview, same caveat as logs above) AND KC_METRICS_ENABLED=true set alongside it — confirmed via Keycloak's own docs: "Available only when metrics and feature 'opentelemetry-metrics:v1' are enabled." Proposing KC_TELEMETRY_METRICS_ENABLED alone, without also setting KC_METRICS_ENABLED=true, silently does nothing. |
Diff format per manifest type
Propose additions in the syntax of whatever service.deployment.configFiles actually contains —
never assume one shape:
- Kubernetes Deployment/StatefulSet manifest, or Helm values.yaml: an
env:list entry per variable (- name: KC_TRACING_ENABLED\n value: "true"), inserted into the existing container'senv:block — read the file first to match its existing indentation and quoting style exactly, the same "extend, never clobber" disciplineinstrumentation-genapplies to a pre-existinginstrumentation.ts. - docker-compose.yml: an
environment:map entry (KC_TRACING_ENABLED: "true", or the list form- KC_TRACING_ENABLED=true— match whichever form the file already uses). - Dockerfile: an
ENV KC_TRACING_ENABLED=trueline, only when the image is built from this Dockerfile rather than pulled as-is — aFROM quay.io/keycloak/keycloakwith no further customization has nowhere in the Dockerfile for this to usefully live; say so and point at the orchestration manifest instead.
Always show a unified diff (--- a/<path> / +++ b/<path>, @@ hunk headers) against the
actual file content you read, never a bare "add these lines" list divorced from real context —
the reader needs to see exactly where it goes and what it neighbors.
What this is not
/otel-remediate (v1) only prints the proposed diff — it never writes. Unlike a generated
SDK bootstrap file (which this plugin owns and can safely regenerate under write-guard), a
Kubernetes Deployment manifest or docker-compose file is infrastructure the plugin does not own
and was not the one to create; write-guard's ownership-marker contract doesn't apply to it, and a
wrong automated edit here has a materially higher blast radius (a live cluster resource) than a
wrong edit to a bootstrap file the plugin generated in the first place. Print-only is not a
missing feature to add later casually — treat "should this write automatically" as its own
deliberate decision, not a default to slide into.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

