This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-jbang-examples.git
The following commit(s) were added to refs/heads/main by this push:
new 66b6871 Add example catalog system with metadata, generator, and
beginner examples
66b6871 is described below
commit 66b687155644bd964b49c92906797b01034bd7b3
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed May 20 15:10:00 2026 +0200
Add example catalog system with metadata, generator, and beginner examples
Add metadata.json to each example with title, description, tags, level
(beginner/intermediate/advanced), bundled flag, and exclude flag.
Add generate-catalog.sh script that produces
camel-jbang-example-catalog.json
from the metadata files. The catalog is consumed by camel-jbang to power
the `camel run --example` and `--example-list` commands.
Add three beginner examples (timer-log, rest-api, cron-log) that were
previously hardcoded in camel-jbang, plus missing READMEs for kubernetes
examples.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
artemis/metadata.json | 11 +
aws/aws-s3-event-based/metadata.json | 13 +
aws/aws-sqs/metadata.json | 12 +
camel-jbang-example-catalog.json | 436 ++++++++++++++++++++++++++++++
circuit-breaker/metadata.json | 10 +
cron-log/README.adoc | 7 +
cron-log/cron-log.camel.yaml | 10 +
cron-log/metadata.json | 12 +
docling-langchain4j-rag/metadata.json | 12 +
edi-x12-as2/metadata.json | 13 +
financial-doc-analyzer/metadata.json | 12 +
ftp/metadata.json | 11 +
generate-catalog.sh | 106 ++++++++
groovy/metadata.json | 11 +
ibm/ibm-cos/metadata.json | 13 +
ibm/ibm-watson-language/metadata.json | 13 +
keycloak-introspection-rest/metadata.json | 12 +
keycloak-ldap-migration/metadata.json | 13 +
keycloak-security-rest/metadata.json | 12 +
kubernetes/secrets/README.adoc | 13 +
kubernetes/secrets/metadata.json | 11 +
kubernetes/service/README.adoc | 11 +
kubernetes/service/metadata.json | 11 +
mqtt/metadata.json | 11 +
ocsf/metadata.json | 12 +
openai/pii-redaction/metadata.json | 12 +
openapi/client/metadata.json | 11 +
openapi/server/metadata.json | 11 +
pqc-document-signing/metadata.json | 13 +
pqc-secure-file-transfer/metadata.json | 13 +
rest-api/README.adoc | 12 +
rest-api/metadata.json | 11 +
rest-api/rest-api.camel.yaml | 21 ++
routes/metadata.json | 11 +
smart-log-analyzer/metadata.json | 12 +
sql/metadata.json | 11 +
timer-log/README.adoc | 7 +
timer-log/metadata.json | 11 +
timer-log/timer-log.camel.yaml | 10 +
xslt/metadata.json | 11 +
40 files changed, 985 insertions(+)
diff --git a/artemis/metadata.json b/artemis/metadata.json
new file mode 100644
index 0000000..a225846
--- /dev/null
+++ b/artemis/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Apache ActiveMQ Artemis",
+ "description": "Setup connection factory to a remote Apache ActiveMQ
Artemis messaging broker",
+ "tags": [
+ "messaging",
+ "jms",
+ "artemis"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/aws/aws-s3-event-based/metadata.json
b/aws/aws-s3-event-based/metadata.json
new file mode 100644
index 0000000..4a39ab6
--- /dev/null
+++ b/aws/aws-s3-event-based/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "AWS S3 CDC",
+ "description": "Consume S3 events using EventBridge and SQS for change
data capture",
+ "tags": [
+ "aws",
+ "s3",
+ "sqs",
+ "eventbridge",
+ "cloud"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/aws/aws-sqs/metadata.json b/aws/aws-sqs/metadata.json
new file mode 100644
index 0000000..4da709b
--- /dev/null
+++ b/aws/aws-sqs/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "AWS SQS Sink",
+ "description": "Push messages to AWS SQS queue via HTTP service",
+ "tags": [
+ "aws",
+ "sqs",
+ "http",
+ "cloud"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/camel-jbang-example-catalog.json b/camel-jbang-example-catalog.json
new file mode 100644
index 0000000..cdd5c70
--- /dev/null
+++ b/camel-jbang-example-catalog.json
@@ -0,0 +1,436 @@
+[
+ {
+ "name": "artemis",
+ "title": "Apache ActiveMQ Artemis",
+ "description": "Setup connection factory to a remote Apache ActiveMQ
Artemis messaging broker",
+ "level": "intermediate",
+ "tags": [
+ "messaging",
+ "jms",
+ "artemis"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "consumer.camel.yaml",
+ "producer.camel.yaml"
+ ]
+ },
+ {
+ "name": "aws/aws-s3-event-based",
+ "title": "AWS S3 CDC",
+ "description": "Consume S3 events using EventBridge and SQS for change
data capture",
+ "level": "advanced",
+ "tags": [
+ "aws",
+ "s3",
+ "sqs",
+ "eventbridge",
+ "cloud"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "aws-s3-cdc-log.camel.yaml",
+ "example-file.txt",
+ "policy-queue.json",
+ "terraform/main.tf"
+ ]
+ },
+ {
+ "name": "aws/aws-sqs",
+ "title": "AWS SQS Sink",
+ "description": "Push messages to AWS SQS queue via HTTP service",
+ "level": "advanced",
+ "tags": [
+ "aws",
+ "sqs",
+ "http",
+ "cloud"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "http-to-aws-sqs.camel.yaml"
+ ]
+ },
+ {
+ "name": "circuit-breaker",
+ "title": "Circuit Breaker",
+ "description": "Use the circuit breaker EIP for fault tolerance",
+ "level": "beginner",
+ "tags": [
+ "eip",
+ "resilience"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "route.camel.yaml"
+ ]
+ },
+ {
+ "name": "cron-log",
+ "title": "Cron Log",
+ "description": "Scheduled task that logs every 5 seconds",
+ "level": "beginner",
+ "tags": [
+ "beginner",
+ "timer",
+ "cron",
+ "log"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "cron-log.camel.yaml"
+ ]
+ },
+ {
+ "name": "docling-langchain4j-rag",
+ "title": "Document Analysis with Docling and LangChain4j RAG",
+ "description": "RAG workflow combining Docling document conversion
with LangChain4j and Ollama",
+ "level": "advanced",
+ "tags": [
+ "ai",
+ "rag",
+ "langchain4j",
+ "docling"
+ ],
+ "bundled": false,
+ "requiresDocker": true,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "compose.yaml",
+ "docling-langchain4j-rag.yaml",
+ "sample.md"
+ ]
+ },
+ {
+ "name": "financial-doc-analyzer",
+ "title": "Financial Document Analyzer",
+ "description": "Automated financial document analysis with Docling,
LangChain4j, and market data",
+ "level": "advanced",
+ "tags": [
+ "ai",
+ "langchain4j",
+ "docling",
+ "finance"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "examples/banking-sector-brief.pdf",
+ "examples/magnificent-seven-update.pdf",
+ "examples/semiconductor-sector-analysis.pdf",
+ "examples/tesla-q3-2024.pdf",
+ "financial-doc-analyzer.yaml"
+ ]
+ },
+ {
+ "name": "ftp",
+ "title": "ActiveMQ to FTP",
+ "description": "Integrate ActiveMQ messaging with an FTP server",
+ "level": "intermediate",
+ "tags": [
+ "messaging",
+ "ftp",
+ "activemq"
+ ],
+ "bundled": false,
+ "requiresDocker": true,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "compose.yaml",
+ "ftp.camel.yaml",
+ "jbang.properties"
+ ]
+ },
+ {
+ "name": "groovy",
+ "title": "Groovy",
+ "description": "Use Groovy with extra dependencies and content-based
routing",
+ "level": "beginner",
+ "tags": [
+ "language",
+ "groovy",
+ "eip"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "groovy.camel.yaml"
+ ]
+ },
+ {
+ "name": "keycloak-introspection-rest",
+ "title": "Keycloak Token Introspection REST API",
+ "description": "Secure REST APIs with Keycloak OAuth 2.0 token
introspection",
+ "level": "advanced",
+ "tags": [
+ "security",
+ "keycloak",
+ "rest",
+ "oauth"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "rest-api.camel.yaml"
+ ]
+ },
+ {
+ "name": "keycloak-security-rest",
+ "title": "Keycloak Security REST API",
+ "description": "Secure REST APIs with Keycloak authentication and
authorization",
+ "level": "advanced",
+ "tags": [
+ "security",
+ "keycloak",
+ "rest",
+ "oauth"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "rest-api.camel.yaml"
+ ]
+ },
+ {
+ "name": "mqtt",
+ "title": "MQTT",
+ "description": "Receive MQTT events from an external MQTT broker",
+ "level": "intermediate",
+ "tags": [
+ "messaging",
+ "mqtt",
+ "iot"
+ ],
+ "bundled": false,
+ "requiresDocker": true,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "compose.yaml",
+ "infra/mosquitto.conf",
+ "mqtt.camel.yaml",
+ "start.sh"
+ ]
+ },
+ {
+ "name": "openai/pii-redaction",
+ "title": "OpenAI PII Redaction",
+ "description": "Redact personal identifiable information from text
using OpenAI-compatible LLMs",
+ "level": "advanced",
+ "tags": [
+ "ai",
+ "openai",
+ "privacy",
+ "security"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "pii-redaction.camel.yaml",
+ "pii.schema.json"
+ ]
+ },
+ {
+ "name": "openapi/client",
+ "title": "OpenAPI Client",
+ "description": "REST client generated from an OpenAPI specification",
+ "level": "intermediate",
+ "tags": [
+ "rest",
+ "openapi",
+ "client"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "examples/1001.json",
+ "petstore-api.json",
+ "petstore-client.camel.yaml"
+ ]
+ },
+ {
+ "name": "openapi/server",
+ "title": "OpenAPI Server",
+ "description": "REST service implemented from an OpenAPI
specification",
+ "level": "intermediate",
+ "tags": [
+ "rest",
+ "openapi",
+ "server"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "examples/pet/1000.json",
+ "petstore-api.json",
+ "petstore.camel.yaml"
+ ]
+ },
+ {
+ "name": "rest-api",
+ "title": "REST API",
+ "description": "REST API with hello endpoints",
+ "level": "beginner",
+ "tags": [
+ "beginner",
+ "rest",
+ "http"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "rest-api.camel.yaml"
+ ]
+ },
+ {
+ "name": "routes",
+ "title": "Routes",
+ "description": "Define routes in YAML with Java beans",
+ "level": "beginner",
+ "tags": [
+ "beginner",
+ "yaml",
+ "bean"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "Greeter.java",
+ "README.adoc",
+ "beans.yaml",
+ "routes.camel.yaml"
+ ]
+ },
+ {
+ "name": "smart-log-analyzer",
+ "title": "Smart Log Analyzer",
+ "description": "Intelligent observability correlating OpenTelemetry
logs and traces with LLM analysis",
+ "level": "advanced",
+ "tags": [
+ "ai",
+ "observability",
+ "opentelemetry",
+ "logging"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "analyzer/application-dev.properties",
+ "analyzer/error-analyzer.camel.yaml",
+ "containers/caches/infinispan-events-config.json",
+ "containers/caches/infinispan-events-to-process-config.json",
+ "containers/docker-compose.yaml",
+ "containers/otel-collector-config.yaml",
+ "correlator/application-dev.properties",
+ "correlator/correlated-log-schema.json",
+ "correlator/correlated-trace-schema.json",
+ "correlator/infinispan.camel.yaml",
+ "correlator/kafka-ca-cert.pem",
+ "correlator/kaoto-datamapper-4a94acc3.xsl",
+ "correlator/kaoto-datamapper-8f5bb2dd.xsl",
+ "correlator/logs-mapper.camel.yaml",
+ "correlator/otel-log-record-schema.json",
+ "correlator/otel-logs-schema.json",
+ "correlator/otel-span-schema.json",
+ "correlator/otel-traces-schema.json",
+ "correlator/traces-mapper.camel.yaml",
+ "first-iteration/analyzer.camel.yaml",
+ "first-iteration/application.properties",
+ "first-iteration/load-generator.camel.yaml",
+ "log-generator/agent.properties",
+ "log-generator/application-dev.properties",
+ "log-generator/log-generator.camel.yaml",
+ "log-generator/opentelemetry-javaagent.jar",
+ "ui-console/application-dev.properties",
+ "ui-console/index.html",
+ "ui-console/jms-file-storage.camel.yaml",
+ "ui-console/rest-api.camel.yaml"
+ ]
+ },
+ {
+ "name": "sql",
+ "title": "SQL Database",
+ "description": "Use a SQL database with Camel and Postgres",
+ "level": "intermediate",
+ "tags": [
+ "database",
+ "sql",
+ "postgres"
+ ],
+ "bundled": false,
+ "requiresDocker": true,
+ "files": [
+ "README.adoc",
+ "application.properties",
+ "compose.yaml",
+ "sql.camel.yaml"
+ ]
+ },
+ {
+ "name": "timer-log",
+ "title": "Timer Log",
+ "description": "Simple timer that logs a hello message every second",
+ "level": "beginner",
+ "tags": [
+ "beginner",
+ "timer",
+ "log"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "timer-log.camel.yaml"
+ ]
+ },
+ {
+ "name": "xslt",
+ "title": "XSLT Transformation",
+ "description": "Basic XML transformation using XSLT style sheets",
+ "level": "beginner",
+ "tags": [
+ "transformation",
+ "xml",
+ "xslt"
+ ],
+ "bundled": true,
+ "requiresDocker": false,
+ "files": [
+ "README.adoc",
+ "consumer.camel.yaml",
+ "input/account.xml",
+ "stylesheet.xsl"
+ ]
+ }
+]
diff --git a/circuit-breaker/metadata.json b/circuit-breaker/metadata.json
new file mode 100644
index 0000000..a9abd62
--- /dev/null
+++ b/circuit-breaker/metadata.json
@@ -0,0 +1,10 @@
+{
+ "title": "Circuit Breaker",
+ "description": "Use the circuit breaker EIP for fault tolerance",
+ "tags": [
+ "eip",
+ "resilience"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/cron-log/README.adoc b/cron-log/README.adoc
new file mode 100644
index 0000000..7a57211
--- /dev/null
+++ b/cron-log/README.adoc
@@ -0,0 +1,7 @@
+== Cron Log
+
+This example shows a scheduled task that logs the current time every 5 seconds.
+
+=== How to run
+
+ camel run cron-log.camel.yaml
diff --git a/cron-log/cron-log.camel.yaml b/cron-log/cron-log.camel.yaml
new file mode 100644
index 0000000..c31bdb1
--- /dev/null
+++ b/cron-log/cron-log.camel.yaml
@@ -0,0 +1,10 @@
+- route:
+ id: cron-log
+ from:
+ uri: timer:cron
+ parameters:
+ period: "5000"
+ steps:
+ - setBody:
+ simple: "Scheduled task running at ${date:now:HH:mm:ss}"
+ - log: "${body}"
diff --git a/cron-log/metadata.json b/cron-log/metadata.json
new file mode 100644
index 0000000..41e400e
--- /dev/null
+++ b/cron-log/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Cron Log",
+ "description": "Scheduled task that logs every 5 seconds",
+ "tags": [
+ "beginner",
+ "timer",
+ "cron",
+ "log"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/docling-langchain4j-rag/metadata.json
b/docling-langchain4j-rag/metadata.json
new file mode 100644
index 0000000..4f15252
--- /dev/null
+++ b/docling-langchain4j-rag/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Document Analysis with Docling and LangChain4j RAG",
+ "description": "RAG workflow combining Docling document conversion with
LangChain4j and Ollama",
+ "tags": [
+ "ai",
+ "rag",
+ "langchain4j",
+ "docling"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/edi-x12-as2/metadata.json b/edi-x12-as2/metadata.json
new file mode 100644
index 0000000..3174d43
--- /dev/null
+++ b/edi-x12-as2/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "EDI X12 over AS2",
+ "description": "Supply chain EDI X12 transaction flow over AS2 with
Smooks",
+ "tags": [
+ "edi",
+ "as2",
+ "smooks",
+ "supply-chain"
+ ],
+ "bundled": false,
+ "level": "advanced",
+ "exclude": true
+}
diff --git a/financial-doc-analyzer/metadata.json
b/financial-doc-analyzer/metadata.json
new file mode 100644
index 0000000..c0df12d
--- /dev/null
+++ b/financial-doc-analyzer/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Financial Document Analyzer",
+ "description": "Automated financial document analysis with Docling,
LangChain4j, and market data",
+ "tags": [
+ "ai",
+ "langchain4j",
+ "docling",
+ "finance"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/ftp/metadata.json b/ftp/metadata.json
new file mode 100644
index 0000000..59a8265
--- /dev/null
+++ b/ftp/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "ActiveMQ to FTP",
+ "description": "Integrate ActiveMQ messaging with an FTP server",
+ "tags": [
+ "messaging",
+ "ftp",
+ "activemq"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/generate-catalog.sh b/generate-catalog.sh
new file mode 100755
index 0000000..61f248e
--- /dev/null
+++ b/generate-catalog.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Generates camel-jbang-example-catalog.json from metadata.json files.
+#
+# Usage: ./generate-catalog.sh
+#
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+CATALOG_FILE="$SCRIPT_DIR/camel-jbang-example-catalog.json"
+
+python3 - "$SCRIPT_DIR" "$CATALOG_FILE" << 'PYEOF'
+import json
+import os
+import sys
+
+repo_root = sys.argv[1]
+catalog_file = sys.argv[2]
+
+SKIP_FILES = {
+ "metadata.json",
+ ".gitignore", ".DS_Store"
+}
+SKIP_EXTENSIONS = {
+ ".png", ".jpg", ".jpeg", ".gif", ".svg",
+ ".excalidraw", ".iml"
+}
+
+catalog = []
+
+for dirpath, dirnames, filenames in sorted(os.walk(repo_root)):
+ # skip hidden directories
+ dirnames[:] = [d for d in dirnames if not d.startswith(".")]
+
+ if "metadata.json" not in filenames:
+ continue
+
+ meta_path = os.path.join(dirpath, "metadata.json")
+ with open(meta_path) as f:
+ meta = json.load(f)
+
+ if meta.get("exclude", False):
+ continue
+
+ name = os.path.relpath(dirpath, repo_root)
+
+ SKIP_DIRS = {"test", "target", "node_modules"}
+
+ # collect example files recursively (skip
metadata/readme/images/hidden/test dirs)
+ files = []
+ for sub_dirpath, sub_dirnames, sub_filenames in os.walk(dirpath):
+ sub_dirnames[:] = [
+ d for d in sub_dirnames
+ if not d.startswith(".") and d not in SKIP_DIRS
+ ]
+ # skip subdirs that have their own metadata.json (they are separate
examples)
+ sub_dirnames[:] = [
+ d for d in sub_dirnames
+ if not os.path.exists(os.path.join(sub_dirpath, d,
"metadata.json"))
+ ]
+ for f in sub_filenames:
+ if (f not in SKIP_FILES
+ and not f.startswith(".")
+ and os.path.splitext(f)[1].lower() not in SKIP_EXTENSIONS):
+ rel = os.path.relpath(os.path.join(sub_dirpath, f), dirpath)
+ files.append(rel)
+ files.sort()
+
+ requires_docker = "compose.yaml" in filenames or "docker-compose.yaml" in
filenames
+
+ entry = {
+ "name": name,
+ "title": meta["title"],
+ "description": meta["description"],
+ "level": meta.get("level", "intermediate"),
+ "tags": meta.get("tags", []),
+ "bundled": meta.get("bundled", False),
+ "requiresDocker": requires_docker,
+ "files": files,
+ }
+ catalog.append(entry)
+
+with open(catalog_file, "w") as f:
+ json.dump(catalog, f, indent=4)
+ f.write("\n")
+
+print(f"Generated {catalog_file} with {len(catalog)} examples")
+PYEOF
diff --git a/groovy/metadata.json b/groovy/metadata.json
new file mode 100644
index 0000000..b2c51dd
--- /dev/null
+++ b/groovy/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Groovy",
+ "description": "Use Groovy with extra dependencies and content-based
routing",
+ "tags": [
+ "language",
+ "groovy",
+ "eip"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/ibm/ibm-cos/metadata.json b/ibm/ibm-cos/metadata.json
new file mode 100644
index 0000000..757e5a5
--- /dev/null
+++ b/ibm/ibm-cos/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "IBM Cloud Object Storage",
+ "description": "IBM COS Kamelets for cloud object storage operations",
+ "tags": [
+ "ibm",
+ "cloud",
+ "storage",
+ "kamelet"
+ ],
+ "bundled": false,
+ "level": "advanced",
+ "exclude": true
+}
diff --git a/ibm/ibm-watson-language/metadata.json
b/ibm/ibm-watson-language/metadata.json
new file mode 100644
index 0000000..76df5ce
--- /dev/null
+++ b/ibm/ibm-watson-language/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "IBM Watson Natural Language Understanding",
+ "description": "Analyze text with IBM Watson NLU for sentiment, entities,
and concepts",
+ "tags": [
+ "ibm",
+ "ai",
+ "watson",
+ "nlp"
+ ],
+ "bundled": false,
+ "level": "advanced",
+ "exclude": true
+}
diff --git a/keycloak-introspection-rest/metadata.json
b/keycloak-introspection-rest/metadata.json
new file mode 100644
index 0000000..0569aa7
--- /dev/null
+++ b/keycloak-introspection-rest/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Keycloak Token Introspection REST API",
+ "description": "Secure REST APIs with Keycloak OAuth 2.0 token
introspection",
+ "tags": [
+ "security",
+ "keycloak",
+ "rest",
+ "oauth"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/keycloak-ldap-migration/metadata.json
b/keycloak-ldap-migration/metadata.json
new file mode 100644
index 0000000..c9c9cb4
--- /dev/null
+++ b/keycloak-ldap-migration/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "LDAP to Keycloak User Migration",
+ "description": "Migrate users from LDAP directory to Keycloak using bulk
operations",
+ "tags": [
+ "security",
+ "keycloak",
+ "ldap",
+ "migration"
+ ],
+ "bundled": false,
+ "level": "advanced",
+ "exclude": true
+}
diff --git a/keycloak-security-rest/metadata.json
b/keycloak-security-rest/metadata.json
new file mode 100644
index 0000000..d9f11e0
--- /dev/null
+++ b/keycloak-security-rest/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Keycloak Security REST API",
+ "description": "Secure REST APIs with Keycloak authentication and
authorization",
+ "tags": [
+ "security",
+ "keycloak",
+ "rest",
+ "oauth"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/kubernetes/secrets/README.adoc b/kubernetes/secrets/README.adoc
new file mode 100644
index 0000000..185f36b
--- /dev/null
+++ b/kubernetes/secrets/README.adoc
@@ -0,0 +1,13 @@
+== Kubernetes Secrets
+
+This example shows how to use Kubernetes secrets for configuration properties
in a Camel route.
+
+The route exposes a REST endpoint that returns a news headline read from a
Kubernetes secret.
+
+=== How to run
+
+First, deploy to Kubernetes:
+
+ camel kubernetes run news-service.camel.yaml application.properties
+
+The secret `news.headline` is mounted from `/etc/camel/secrets/` as configured
in `application.properties`.
diff --git a/kubernetes/secrets/metadata.json b/kubernetes/secrets/metadata.json
new file mode 100644
index 0000000..1ac9651
--- /dev/null
+++ b/kubernetes/secrets/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Kubernetes Secrets",
+ "description": "Use Kubernetes secrets for configuration properties",
+ "tags": [
+ "kubernetes",
+ "secrets",
+ "cloud"
+ ],
+ "bundled": false,
+ "exclude": true
+}
diff --git a/kubernetes/service/README.adoc b/kubernetes/service/README.adoc
new file mode 100644
index 0000000..ca8ced6
--- /dev/null
+++ b/kubernetes/service/README.adoc
@@ -0,0 +1,11 @@
+== Kubernetes Service
+
+This example shows how to run a simple Camel REST service on Kubernetes.
+
+The route exposes a REST endpoint at `/news` that returns a hello message.
+
+=== How to run
+
+Deploy to Kubernetes:
+
+ camel kubernetes run news-service.camel.yaml
diff --git a/kubernetes/service/metadata.json b/kubernetes/service/metadata.json
new file mode 100644
index 0000000..f8c0954
--- /dev/null
+++ b/kubernetes/service/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Kubernetes Service",
+ "description": "Run a Camel service on Kubernetes",
+ "tags": [
+ "kubernetes",
+ "cloud",
+ "service"
+ ],
+ "bundled": false,
+ "exclude": true
+}
diff --git a/mqtt/metadata.json b/mqtt/metadata.json
new file mode 100644
index 0000000..a91e4f4
--- /dev/null
+++ b/mqtt/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "MQTT",
+ "description": "Receive MQTT events from an external MQTT broker",
+ "tags": [
+ "messaging",
+ "mqtt",
+ "iot"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/ocsf/metadata.json b/ocsf/metadata.json
new file mode 100644
index 0000000..7441ecb
--- /dev/null
+++ b/ocsf/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "OCSF DataFormat",
+ "description": "Open Cybersecurity Schema Framework data format with REST
endpoints",
+ "tags": [
+ "security",
+ "ocsf",
+ "dataformat"
+ ],
+ "bundled": false,
+ "level": "intermediate",
+ "exclude": true
+}
diff --git a/openai/pii-redaction/metadata.json
b/openai/pii-redaction/metadata.json
new file mode 100644
index 0000000..67349f3
--- /dev/null
+++ b/openai/pii-redaction/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "OpenAI PII Redaction",
+ "description": "Redact personal identifiable information from text using
OpenAI-compatible LLMs",
+ "tags": [
+ "ai",
+ "openai",
+ "privacy",
+ "security"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/openapi/client/metadata.json b/openapi/client/metadata.json
new file mode 100644
index 0000000..85c56d5
--- /dev/null
+++ b/openapi/client/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "OpenAPI Client",
+ "description": "REST client generated from an OpenAPI specification",
+ "tags": [
+ "rest",
+ "openapi",
+ "client"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/openapi/server/metadata.json b/openapi/server/metadata.json
new file mode 100644
index 0000000..db4da76
--- /dev/null
+++ b/openapi/server/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "OpenAPI Server",
+ "description": "REST service implemented from an OpenAPI specification",
+ "tags": [
+ "rest",
+ "openapi",
+ "server"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/pqc-document-signing/metadata.json
b/pqc-document-signing/metadata.json
new file mode 100644
index 0000000..52991f0
--- /dev/null
+++ b/pqc-document-signing/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "Post-Quantum Document Signing",
+ "description": "Document signing with post-quantum cryptography and
HashiCorp Vault",
+ "tags": [
+ "security",
+ "pqc",
+ "vault",
+ "cryptography"
+ ],
+ "bundled": false,
+ "level": "advanced",
+ "exclude": true
+}
diff --git a/pqc-secure-file-transfer/metadata.json
b/pqc-secure-file-transfer/metadata.json
new file mode 100644
index 0000000..6ac88f0
--- /dev/null
+++ b/pqc-secure-file-transfer/metadata.json
@@ -0,0 +1,13 @@
+{
+ "title": "Post-Quantum Secure File Transfer",
+ "description": "Secure file transfer using ML-KEM post-quantum key
encapsulation",
+ "tags": [
+ "security",
+ "pqc",
+ "file",
+ "cryptography"
+ ],
+ "bundled": false,
+ "level": "intermediate",
+ "exclude": true
+}
diff --git a/rest-api/README.adoc b/rest-api/README.adoc
new file mode 100644
index 0000000..c68c287
--- /dev/null
+++ b/rest-api/README.adoc
@@ -0,0 +1,12 @@
+== REST API
+
+This example shows a REST API with hello endpoints.
+
+=== How to run
+
+ camel run rest-api.camel.yaml
+
+=== Try it
+
+ curl http://localhost:8080/api/hello
+ curl http://localhost:8080/api/hello/World
diff --git a/rest-api/metadata.json b/rest-api/metadata.json
new file mode 100644
index 0000000..43f80d2
--- /dev/null
+++ b/rest-api/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "REST API",
+ "description": "REST API with hello endpoints",
+ "tags": [
+ "beginner",
+ "rest",
+ "http"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/rest-api/rest-api.camel.yaml b/rest-api/rest-api.camel.yaml
new file mode 100644
index 0000000..2e1035c
--- /dev/null
+++ b/rest-api/rest-api.camel.yaml
@@ -0,0 +1,21 @@
+- rest:
+ path: /api
+ get:
+ - path: /hello
+ to: direct:hello
+ - path: /hello/{name}
+ to: direct:hello-name
+- route:
+ id: hello
+ from:
+ uri: direct:hello
+ steps:
+ - setBody:
+ constant: "Hello from Camel REST API!"
+- route:
+ id: hello-name
+ from:
+ uri: direct:hello-name
+ steps:
+ - setBody:
+ simple: "Hello ${header.name} from Camel REST API!"
diff --git a/routes/metadata.json b/routes/metadata.json
new file mode 100644
index 0000000..7f5e492
--- /dev/null
+++ b/routes/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Routes",
+ "description": "Define routes in YAML with Java beans",
+ "tags": [
+ "beginner",
+ "yaml",
+ "bean"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/smart-log-analyzer/metadata.json b/smart-log-analyzer/metadata.json
new file mode 100644
index 0000000..e9e248f
--- /dev/null
+++ b/smart-log-analyzer/metadata.json
@@ -0,0 +1,12 @@
+{
+ "title": "Smart Log Analyzer",
+ "description": "Intelligent observability correlating OpenTelemetry logs
and traces with LLM analysis",
+ "tags": [
+ "ai",
+ "observability",
+ "opentelemetry",
+ "logging"
+ ],
+ "bundled": false,
+ "level": "advanced"
+}
diff --git a/sql/metadata.json b/sql/metadata.json
new file mode 100644
index 0000000..f162617
--- /dev/null
+++ b/sql/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "SQL Database",
+ "description": "Use a SQL database with Camel and Postgres",
+ "tags": [
+ "database",
+ "sql",
+ "postgres"
+ ],
+ "bundled": false,
+ "level": "intermediate"
+}
diff --git a/timer-log/README.adoc b/timer-log/README.adoc
new file mode 100644
index 0000000..3abb3a0
--- /dev/null
+++ b/timer-log/README.adoc
@@ -0,0 +1,7 @@
+== Timer Log
+
+This example shows a simple timer that logs a hello message every second.
+
+=== How to run
+
+ camel run timer-log.camel.yaml
diff --git a/timer-log/metadata.json b/timer-log/metadata.json
new file mode 100644
index 0000000..11dfc4b
--- /dev/null
+++ b/timer-log/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "Timer Log",
+ "description": "Simple timer that logs a hello message every second",
+ "tags": [
+ "beginner",
+ "timer",
+ "log"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}
diff --git a/timer-log/timer-log.camel.yaml b/timer-log/timer-log.camel.yaml
new file mode 100644
index 0000000..cdff71b
--- /dev/null
+++ b/timer-log/timer-log.camel.yaml
@@ -0,0 +1,10 @@
+- route:
+ id: timer-log
+ from:
+ uri: timer:tick
+ parameters:
+ period: "1000"
+ steps:
+ - setBody:
+ simple: "Hello Camel! (message
#${exchangeProperty.CamelTimerCounter})"
+ - log: "${body}"
diff --git a/xslt/metadata.json b/xslt/metadata.json
new file mode 100644
index 0000000..237fe70
--- /dev/null
+++ b/xslt/metadata.json
@@ -0,0 +1,11 @@
+{
+ "title": "XSLT Transformation",
+ "description": "Basic XML transformation using XSLT style sheets",
+ "tags": [
+ "transformation",
+ "xml",
+ "xslt"
+ ],
+ "bundled": true,
+ "level": "beginner"
+}