You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/10/02 09:08:13 UTC

(camel) 01/01: CAMEL-25261: camel-jbang - bundle the examples of the ladder that run offline (resync of the example catalog)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch chore/CAMEL-25261-sync-bundled-examples
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 42bacbd46d6d2177b23d639fd54ffcfb21198efa
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Oct 2 11:07:59 2026 +0200

    CAMEL-25261: camel-jbang - bundle the examples of the ladder that run offline (resync of the example catalog)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../examples/camel-jbang-example-catalog.json      |  56 +++---
 .../examples/connect/file-processing/README.md     |  78 ++++++++
 .../connect/file-processing/application.properties |  16 ++
 .../file-processing/file-processing.camel.yaml     |  56 ++++++
 .../file-processing/samples/invoice-2001.json      |   1 +
 .../file-processing/samples/invoice-2002.json      |   1 +
 .../file-processing/samples/invoice-2003.json      |   1 +
 .../file-processing/samples/invoice-2004.json      |   1 +
 .../connect/file-processing/samples/note-2005.txt  |   1 +
 .../examples/connect/http-client/README.md         |  77 ++++++++
 .../connect/http-client/application.properties     |  18 ++
 .../connect/http-client/http-client.camel.yaml     | 117 ++++++++++++
 .../connect/http-client/orders/order-1001.json     |   2 +
 .../connect/http-client/orders/order-1002.json     |   2 +
 .../connect/http-client/orders/order-1003.json     |   2 +
 .../examples/connect/http-client/stock.json        |   5 +
 .../resources/examples/connect/stock-api/README.md |  80 ++++++++
 .../connect/stock-api/application.properties       |  18 ++
 .../connect/stock-api/stock-api.camel.yaml         |  73 ++++++++
 .../examples/connect/stock-api/stock.json          |   5 +
 .../examples/contracts/openapi-client/README.md    |  86 +++++++++
 .../openapi-client/application.properties          |  18 ++
 .../openapi-client/openapi-client.camel.yaml       |  64 +++++++
 .../openapi-client/orders/order-1001.json          |   2 +
 .../openapi-client/orders/order-1002.json          |   2 +
 .../openapi-client/orders/order-1003.json          |   2 +
 .../contracts/openapi-client/stock-api.json        | 201 +++++++++++++++++++++
 .../examples/contracts/openapi-server/README.md    |  91 ++++++++++
 .../openapi-server/application.properties          |  18 ++
 .../openapi-server/openapi-server.camel.yaml       | 162 +++++++++++++++++
 .../contracts/openapi-server/stock-api.json        | 201 +++++++++++++++++++++
 .../examples/contracts/openapi-server/stock.json   |   5 +
 .../examples/fail-well/circuit-breaker/README.md   |   3 +-
 .../examples/fail-well/error-handling/README.md    |  82 +++++++++
 .../error-handling/application.properties          |  16 ++
 .../error-handling/error-handling.camel.yaml       |  84 +++++++++
 .../error-handling/orders/order-1001.json          |   2 +
 .../error-handling/orders/order-1002.json          |   2 +
 .../error-handling/orders/order-1003.json          |   2 +
 .../examples/quick-start/rest-api/README.md        |  75 +++++++-
 .../quick-start/rest-api/application.properties    |  17 ++
 .../examples/quick-start/routes/Greeter.java       |  40 ++--
 .../examples/quick-start/routes/README.md          |  85 ++++-----
 .../quick-start/routes/application.properties      |  23 ++-
 .../examples/quick-start/routes/beans.yaml         |   8 +-
 .../examples/quick-start/routes/routes.camel.yaml  |  12 +-
 .../examples/quick-start/splitter/README.md        |  74 +++++---
 .../examples/quick-start/timer-log/README.md       |  70 ++++++-
 .../quick-start/timer-log/application.properties   |  17 ++
 .../resources/examples/route/aggregator/README.md  |  73 ++++++++
 .../route/aggregator/aggregator.camel.yaml         |  52 ++++++
 .../route/aggregator/application.properties        |  16 ++
 .../route/aggregator/orders/order-1001.json        |   2 +
 .../route/aggregator/orders/order-1002.json        |   2 +
 .../route/aggregator/orders/order-1003.json        |   2 +
 .../examples/route/content-based-router/README.md  |  67 +++++++
 .../content-based-router/application.properties    |  16 ++
 .../content-based-router.camel.yaml                |  33 ++++
 .../content-based-router/orders/order-1001.json    |   2 +
 .../content-based-router/orders/order-1002.json    |   2 +
 .../content-based-router/orders/order-1003.json    |   2 +
 .../examples/route/filter-and-multicast/README.md  |  69 +++++++
 .../filter-and-multicast/application.properties    |  16 ++
 .../filter-and-multicast.camel.yaml                |  50 +++++
 .../filter-and-multicast/orders/order-1001.json    |   2 +
 .../filter-and-multicast/orders/order-1002.json    |   2 +
 .../filter-and-multicast/orders/order-1003.json    |   2 +
 .../resources/examples/route/order-lines/README.md |  72 ++++++++
 .../route/order-lines/application.properties       |  16 ++
 .../route/order-lines/order-lines.camel.yaml       |  30 +++
 .../route/order-lines/orders/order-1001.json       |   2 +
 .../route/order-lines/orders/order-1002.json       |   2 +
 .../route/order-lines/orders/order-1003.json       |   2 +
 .../examples/run/nightly-report/README.md          |  64 +++++++
 .../run/nightly-report/application.properties      |  24 +++
 .../run/nightly-report/nightly-report.camel.yaml   |  16 ++
 .../examples/run/order-generator/OrderNumber.java  |  20 ++
 .../examples/run/order-generator/README.md         |  74 ++++++++
 .../run/order-generator/application.properties     |  21 +++
 .../examples/run/order-generator/beans.yaml        |   5 +
 .../run/order-generator/order-generator.camel.yaml |  24 +++
 .../examples/run/properties-and-profiles/README.md |  74 ++++++++
 .../application-prod.properties                    |  21 +++
 .../properties-and-profiles/application.properties |  21 +++
 .../properties-and-profiles.camel.yaml             |  16 ++
 .../examples/transform/csv-to-json/README.md       |  69 +++++++
 .../transform/csv-to-json/application.properties   |  16 ++
 .../transform/csv-to-json/csv-to-json.camel.yaml   |  35 ++++
 .../transform/csv-to-json/inbox/invoices.csv       |   4 +
 .../examples/transform/data-mapping/README.md      |  65 +++++++
 .../transform/data-mapping/application.properties  |  16 ++
 .../transform/data-mapping/data-mapping.camel.yaml |  28 +++
 .../examples/transform/data-mapping/order.json     |   3 +
 .../transform/data-mapping/shipment-mapping.groovy |  12 ++
 .../resources/examples/transform/groovy/README.md  |  67 +++++++
 .../transform/groovy/application.properties        |  19 ++
 .../examples/transform/groovy/groovy.camel.yaml    |  33 ++++
 .../examples/transform/groovy/order-bad-email.json |   2 +
 .../resources/examples/transform/groovy/order.json |   2 +
 .../examples/transform/json-transform/README.md    |  68 +++++++
 .../json-transform/application.properties          |  16 ++
 .../json-transform/json-transform.camel.yaml       |  33 ++++
 .../examples/transform/json-transform/order.json   |   3 +
 .../examples/transform/xml-to-json/README.md       |  67 +++++++
 .../transform/xml-to-json/application.properties   |  16 ++
 .../transform/xml-to-json/inbox/supplier-order.xml |   7 +
 .../transform/xml-to-json/xml-to-json.camel.yaml   |  21 +++
 .../resources/examples/transform/xslt/README.md    |  66 +++++++
 .../examples/transform/xslt/application.properties |  16 ++
 .../transform/xslt/inbox/supplier-order.xml        |   7 +
 .../examples/transform/xslt/packing-slip.xsl       |  15 ++
 .../examples/transform/xslt/xslt.camel.yaml        |  17 ++
 .../src/test/java/camel/example/Greeter.java       |  31 ++--
 .../src/test/java/camel/example/OrderNumber.java   |  40 ++++
 114 files changed, 3637 insertions(+), 145 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
index 0434afa3861f..dbabdbe6816a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
@@ -2,7 +2,7 @@
     {
         "name": "ai/docling-langchain4j-rag",
         "title": "Document Analysis with Docling and LangChain4j RAG",
-        "description": "Documents dropped in a directory are converted by a running Docling service, chunked and summarised by a local Ollama model through langchain4j-chat, and written to an output directory; an HTTP endpoint answers questions against the converted documents.",
+        "description": "Documents dropped in a directory are converted to Markdown by a Docling service, analysed by a local Ollama model through langchain4j-chat, and written as a report to an output directory; an HTTP endpoint answers questions against the latest document.",
         "level": "ai",
         "teaches": {
             "components": [
@@ -42,6 +42,8 @@
             "docling",
             "ollama"
         ],
+        "needs": "a local model",
+        "ciSkip": true,
         "order": 4
     },
     {
@@ -88,6 +90,7 @@
         "infraServices": [
             "ollama"
         ],
+        "needs": "a local model",
         "ciSkip": true,
         "order": 1
     },
@@ -164,6 +167,8 @@
             "pii-redaction.camel.yaml",
             "pii.schema.json"
         ],
+        "needs": "an OpenAI-compatible API",
+        "ciSkip": true,
         "order": 3
     },
     {
@@ -504,7 +509,7 @@
             "inbox",
             "archive"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -555,7 +560,7 @@
             "rest",
             "client"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -601,7 +606,7 @@
             "http",
             "platform-http"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -686,7 +691,7 @@
             "client",
             "contract"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -736,7 +741,7 @@
             "rest",
             "contract"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -818,7 +823,7 @@
             "retry",
             "dead-letter"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -827,8 +832,7 @@
             "error-handling.camel.yaml",
             "orders/order-1001.json",
             "orders/order-1002.json",
-            "orders/order-1003.json",
-            "parked/order-1003.json"
+            "orders/order-1003.json"
         ],
         "order": 1
     },
@@ -856,7 +860,7 @@
         ],
         "bundled": true,
         "requiresDocker": false,
-        "hasCitrusTests": false,
+        "hasCitrusTests": true,
         "files": [
             "README.md",
             "application.properties",
@@ -885,7 +889,7 @@
         ],
         "bundled": true,
         "requiresDocker": false,
-        "hasCitrusTests": false,
+        "hasCitrusTests": true,
         "files": [
             "Greeter.java",
             "README.md",
@@ -920,7 +924,7 @@
         ],
         "bundled": true,
         "requiresDocker": false,
-        "hasCitrusTests": false,
+        "hasCitrusTests": true,
         "files": [
             "README.md",
             "splitter.camel.yaml"
@@ -948,7 +952,7 @@
         ],
         "bundled": true,
         "requiresDocker": false,
-        "hasCitrusTests": false,
+        "hasCitrusTests": true,
         "files": [
             "README.md",
             "application.properties",
@@ -987,7 +991,7 @@
             "aggregator",
             "batch"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1027,7 +1031,7 @@
             "choice",
             "routing"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1069,7 +1073,7 @@
             "filter",
             "multicast"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1110,7 +1114,7 @@
             "splitter",
             "split"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1145,7 +1149,7 @@
             "cron",
             "schedule"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1180,7 +1184,7 @@
             "bean",
             "json"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1215,7 +1219,7 @@
             "profiles",
             "configuration"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1407,7 +1411,7 @@
             "file",
             "transformation"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1448,7 +1452,7 @@
             "json",
             "transformation"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1489,7 +1493,7 @@
             "validation",
             "dependencies"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1530,7 +1534,7 @@
             "jsonpath",
             "transformation"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1567,7 +1571,7 @@
             "jackson",
             "transformation"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
@@ -1599,7 +1603,7 @@
             "xslt",
             "transformation"
         ],
-        "bundled": false,
+        "bundled": true,
         "requiresDocker": false,
         "hasCitrusTests": true,
         "files": [
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/README.md
new file mode 100644
index 000000000000..3444ea6f50f3
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/README.md
@@ -0,0 +1,78 @@
+# File processing
+
+The courier's billing system drops invoices into an inbox directory. Each invoice is checked, archived under a
+month directory and moved to `done`; a bad one goes to `failed`; a file that is not an invoice is left alone.
+The first route plays the courier: it copies the five files in `samples/` into `inbox/`.
+
+## What you will see
+
+```text
+INFO ... file-processing.camel.yaml:47 : Invoice INV-2001 for ORD-1001: 49.4 EUR, archived as 2026-09/invoice-2001.json
+INFO ... file-processing.camel.yaml:47 : Invoice INV-2002 for ORD-1002: 28.5 EUR, archived as 2026-09/invoice-2002.json
+WARN ... file-processing.camel.yaml:11 : Invoice invoice-2003.json rejected: Validation failed for Predicate[bodyOgnl([amount]) > 0]. ...
+ERROR ... DefaultErrorHandler : Failed delivery for (MessageId: ...). Exhausted after delivery attempt: 1 caught: ...PredicateValidationException: ...
+WARN ... GenericFileOnCompletion : Rollback file strategy: ...GenericFileRenameProcessStrategy
+INFO ... file-processing.camel.yaml:47 : Invoice INV-2004 for ORD-1003: 53.45 EUR, archived as 2026-09/invoice-2004.json
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+Afterwards the directories tell the story: `inbox/done/` holds the three good invoices, `inbox/failed/` the
+rejected one, `archive/<year-month>/` copies of the good ones, and `inbox/note-2005.txt` is still where it was.
+Delete `inbox/` and `archive/` to run it again.
+
+## How it works
+
+- The `courier` route is a `file` consumer on `samples/` with `noop: true` writing to `file:inbox`, a copy.
+- The `invoices` route is the lesson: a `file` consumer on `inbox/` with `include: .*\.json`, so the driver's
+  note is never picked up; `move: done` for files that went through, `moveFailed: failed` for files whose
+  exchange failed. Both are directories relative to the inbox.
+- `validate` throws a `PredicateValidationException` when the amount is not positive; the `onException` logs a
+  warning without a stack trace and lets the exception through, which is what makes the consumer use `moveFailed`.
+  Had it set `handled: true`, the file would have been moved to `done` as if it had succeeded.
+- The archive copy uses a `fileName` expression with `${date:now:yyyy-MM}` for the directory and `${file:name}`
+  for the name; the file component creates directories as needed.
+
+## Build it step by step
+
+1. A `file` route on `inbox` that logs `${file:name}`; drop a file in and see it logged, then note the
+   `.camel` directory the consumer moved it to by default.
+2. Add `move: done` and `include: .*\.json`, drop the note in and see it ignored.
+3. Add the `courier` route so the samples arrive by themselves, and `unmarshal` and log the invoice.
+4. Add `validate` and `moveFailed: failed`, then the `onException` to tidy the log.
+
+## Try changing
+
+- Add `idempotent: true` with `idempotentKey: ${file:name}` and drop the same invoice twice.
+- Replace `move: done` with `delete: true`.
+- Point `archive` at a `sftp:` endpoint; the `ftp` example on the next rung shows how.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/file-processing.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/file-processing.citrus.it.yaml
+```
+
+The test starts the routes and verifies the archived and rejected lines.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/file-processing.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/file-processing.camel.yaml
new file mode 100644
index 000000000000..fd9446c3ce86
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/file-processing.camel.yaml
@@ -0,0 +1,56 @@
+# The courier's billing system drops invoices into the inbox. Each invoice
+# is checked, archived by month and moved to done; a bad one goes to failed.
+# The courier route plays the courier: it copies the samples into the inbox.
+- onException:
+    exception:
+      - org.apache.camel.support.processor.PredicateValidationException
+    redeliveryPolicy:
+      logStackTrace: false
+      logExhaustedMessageHistory: false
+    steps:
+      - log:
+          loggingLevel: WARN
+          message: "Invoice ${file:name} rejected: ${exception.message}"
+
+- route:
+    id: courier
+    from:
+      uri: file
+      parameters:
+        directoryName: samples
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - to:
+            uri: file
+            parameters:
+              directoryName: inbox
+
+- route:
+    id: invoices
+    from:
+      uri: file
+      parameters:
+        directoryName: inbox
+        include: ".*\\.json"
+        move: done
+        moveFailed: failed
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - validate:
+            expression:
+              simple:
+                expression: "${body[amount]} > 0"
+        - log:
+            message: "Invoice ${body[invoiceId]} for ${body[orderId]}: ${body[amount]} EUR, archived as ${date:now:yyyy-MM}/${file:name}"
+        - marshal:
+            json:
+              library: Jackson
+        - to:
+            uri: file
+            parameters:
+              directoryName: archive
+              fileName: "${date:now:yyyy-MM}/${file:name}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2001.json
new file mode 100644
index 000000000000..51d79d522de0
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2001.json
@@ -0,0 +1 @@
+{"invoiceId": "INV-2001", "orderId": "ORD-1001", "amount": 49.40, "currency": "EUR"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2002.json
new file mode 100644
index 000000000000..094523603805
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2002.json
@@ -0,0 +1 @@
+{"invoiceId": "INV-2002", "orderId": "ORD-1002", "amount": 28.50, "currency": "EUR"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2003.json
new file mode 100644
index 000000000000..a084e66f4dd1
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2003.json
@@ -0,0 +1 @@
+{"invoiceId": "INV-2003", "orderId": "ORD-1003", "amount": -5.00, "currency": "EUR"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2004.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2004.json
new file mode 100644
index 000000000000..761c24828f0a
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/invoice-2004.json
@@ -0,0 +1 @@
+{"invoiceId": "INV-2004", "orderId": "ORD-1003", "amount": 53.45, "currency": "EUR"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/note-2005.txt b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/note-2005.txt
new file mode 100644
index 000000000000..e82a2d850509
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/file-processing/samples/note-2005.txt
@@ -0,0 +1 @@
+Handwritten note from the driver: parcel for ORD-1002 left with the neighbour.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/README.md
new file mode 100644
index 000000000000..f03565365e6f
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/README.md
@@ -0,0 +1,77 @@
+# HTTP client
+
+Before an order goes to picking, every line is checked against the stock service over HTTP. The stock service
+runs inside this same example, so there is nothing else to start: the first two routes are a trimmed copy of
+`stock-api`, the third is the client.
+
+## What you will see
+
+```text
+INFO ... http-client.camel.yaml:112 : ORD-1001: CAMEL-TSHIRT x 2, 120 in stock, ok
+INFO ... http-client.camel.yaml:112 : ORD-1001: CAMEL-MUG x 1, 42 in stock, ok
+INFO ... http-client.camel.yaml:112 : ORD-1002: CAMEL-MUG x 3, 42 in stock, ok
+INFO ... http-client.camel.yaml:112 : ORD-1003: CAMEL-TSHIRT x 1, 120 in stock, ok
+INFO ... http-client.camel.yaml:116 : ORD-1003: CAMEL-CAP x 1, only 0 in stock, back-order
+INFO ... http-client.camel.yaml:112 : ORD-1003: CAMEL-MUG x 2, 42 in stock, ok
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run can be
+repeated. The stock levels are in `stock.json`.
+
+## How it works
+
+- The client splits each order into lines, as `order-lines` does, and calls `toD` with
+  `http://localhost:8080/stock/${exchangeProperty.sku}`: `toD` because the URI is built per message.
+- The SKU, the quantity and the order id are kept in exchange properties, not headers: headers travel on the
+  HTTP request, and a header named `sku` would collide with the `{sku}` path parameter on the server side.
+  Properties stay in the route.
+- The body is set to null before the call: a GET has no body, and the order line would otherwise be sent. The
+  response replaces the body, which is why the line was saved in properties first.
+- `throwExceptionOnFailure=false` turns a 404 into a normal response with `CamelHttpResponseCode` set, so the
+  `choice` can log it instead of the error handler.
+
+## Build it step by step
+
+1. Start from `stock-api` and add a `file` route on `orders` that logs each order.
+2. Split the lines and call `http://localhost:8080/stock/CAMEL-MUG` with a fixed SKU; log the response body.
+3. Build the URI from the line with `toD` and a property; notice the body is gone after the call.
+4. Add `throwExceptionOnFailure=false` and the `choice` on the response code and the quantity.
+
+## Try changing
+
+- Remove `throwExceptionOnFailure=false` and add a SKU that does not exist to an order: the 404 becomes an
+  `HttpOperationFailedException` handled by the error handler.
+- Call a public API instead, `https://api.github.com/repos/apache/camel` for example, and log `${body[stargazers_count]}`.
+- Set `camel.server.port` to another port and update the URI to match.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/http-client.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/http-client.citrus.it.yaml
+```
+
+The test starts the routes and verifies the ok and back-order lines.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/application.properties
new file mode 100644
index 000000000000..5d54c44f16dc
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/application.properties
@@ -0,0 +1,18 @@
+# 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.
+
+camel.server.port=8080
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/http-client.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/http-client.camel.yaml
new file mode 100644
index 000000000000..79f40db5b295
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/http-client.camel.yaml
@@ -0,0 +1,117 @@
+# Before an order goes to picking, every line is checked against the stock
+# service over HTTP. The stock service runs in this same example, so there
+# is nothing else to start.
+- rest:
+    path: /stock
+    get:
+      - path: "/{sku}"
+        to:
+          uri: direct:one-sku
+
+- route:
+    id: stock-service
+    from:
+      uri: direct
+      parameters:
+        name: one-sku
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: resource:file:stock.json
+        - setBody:
+            expression:
+              jsonpath:
+                expression: "$[?(@.sku == '${header.sku}')]"
+                resultType: java.util.List
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body.size()} == 0"
+                steps:
+                  - setHeader:
+                      name: CamelHttpResponseCode
+                      expression:
+                        constant:
+                          expression: "404"
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: '{"error": "unknown sku ${header.sku}"}'
+            otherwise:
+              steps:
+                - setBody:
+                    expression:
+                      simple:
+                        expression: "${body[0]}"
+                - marshal:
+                    json:
+                      library: Jackson
+        - setHeader:
+            name: Content-Type
+            expression:
+              constant:
+                expression: application/json
+
+- route:
+    id: check-stock
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        # exchange properties stay in the route; headers would travel on the HTTP request
+        - setProperty:
+            name: orderId
+            expression:
+              simple:
+                expression: "${body[orderId]}"
+        - split:
+            expression:
+              simple:
+                expression: "${body[lines]}"
+            steps:
+              - setProperty:
+                  name: sku
+                  expression:
+                    simple:
+                      expression: "${body[sku]}"
+              - setProperty:
+                  name: needed
+                  expression:
+                    simple:
+                      expression: "${body[qty]}"
+              # a GET has no body, and the response replaces whatever the body was
+              - setBody:
+                  expression:
+                    simple:
+                      expression: "${null}"
+              - toD:
+                  uri: "http://localhost:8080/stock/${exchangeProperty.sku}?throwExceptionOnFailure=false"
+              - unmarshal:
+                  json:
+                    library: Jackson
+              - choice:
+                  when:
+                    - expression:
+                        simple:
+                          expression: "${header.CamelHttpResponseCode} != 200"
+                      steps:
+                        - log:
+                            message: "${exchangeProperty.orderId}: ${body[error]} (HTTP ${header.CamelHttpResponseCode})"
+                    - expression:
+                        simple:
+                          expression: "${body[qty]} >= ${exchangeProperty.needed}"
+                      steps:
+                        - log:
+                            message: "${exchangeProperty.orderId}: ${exchangeProperty.sku} x ${exchangeProperty.needed}, ${body[qty]} in stock, ok"
+                  otherwise:
+                    steps:
+                      - log:
+                          message: "${exchangeProperty.orderId}: ${exchangeProperty.sku} x ${exchangeProperty.needed}, only ${body[qty]} in stock, back-order"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/stock.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/stock.json
new file mode 100644
index 000000000000..efab5de3aa66
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/http-client/stock.json
@@ -0,0 +1,5 @@
+[
+  {"sku": "CAMEL-TSHIRT", "qty": 120},
+  {"sku": "CAMEL-MUG", "qty": 42},
+  {"sku": "CAMEL-CAP", "qty": 0}
+]
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/README.md
new file mode 100644
index 000000000000..10cbd834a40f
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/README.md
@@ -0,0 +1,80 @@
+# Stock API
+
+The shop's stock service: what the warehouse has on the shelf, per SKU. A REST API with two operations, served by
+the HTTP server built into the Camel CLI, answering from a JSON file.
+
+## What you will see
+
+```text
+$ curl localhost:8080/stock/CAMEL-MUG
+{"sku":"CAMEL-MUG","qty":42}
+
+$ curl -i localhost:8080/stock/CAMEL-SOCKS
+HTTP/1.1 404 Not Found
+{"error": "unknown sku CAMEL-SOCKS"}
+
+$ curl localhost:8080/stock
+[
+  {"sku": "CAMEL-TSHIRT", "qty": 120},
+  {"sku": "CAMEL-MUG", "qty": 42},
+  {"sku": "CAMEL-CAP", "qty": 0}
+]
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+Then, in another terminal, call it with `curl` as above. Stop it with `ctrl` + `c`.
+
+## How it works
+
+- `rest` with `path: /stock` declares the API: a `get` with no path for the list, a `get` with `/{sku}` for one
+  item. Each operation hands over to a `direct` route. The CLI starts the HTTP server on port 8080 because the
+  file uses the REST DSL; `application.properties` sets the port.
+- The list route sets the body to `resource:file:stock.json`, the file next to the route, and the content type.
+- The item route loads the same file and picks the item with a `jsonpath` filter, `$[?(@.sku == '...')]`, in which
+  the `{sku}` path parameter arrives as the header `sku`. The result is a list: empty means 404 with a small error
+  body, otherwise the first element is marshalled back to JSON.
+- `CamelHttpResponseCode` is the header that sets the status code; 200 is the default.
+
+## Build it step by step
+
+1. A `rest` with one `get` that answers `resource:file:stock.json`; run it and `curl localhost:8080/stock`.
+2. Add the `/{sku}` operation and log `${header.sku}` to see the path parameter arrive.
+3. Filter the file with `jsonpath` and return the first element; `curl` a known SKU.
+4. Add the `choice` for the empty result and the 404.
+
+## Try changing
+
+- Add `POST /stock/{sku}` that logs the body: `curl -X POST -d '{"qty": 5}' localhost:8080/stock/CAMEL-CAP`.
+- Change the port in `application.properties` and see the CLI pick it up.
+- The `http-client` example calls this service from another route.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/stock-api.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/stock-api.citrus.it.yaml
+```
+
+The test starts the service and calls both operations over HTTP, checking the JSON and the 404.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/application.properties
new file mode 100644
index 000000000000..5d54c44f16dc
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/application.properties
@@ -0,0 +1,18 @@
+# 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.
+
+camel.server.port=8080
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock-api.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock-api.camel.yaml
new file mode 100644
index 000000000000..b5464b803204
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock-api.camel.yaml
@@ -0,0 +1,73 @@
+# The shop's stock service: what the warehouse has on the shelf, per SKU.
+# GET /stock lists everything, GET /stock/{sku} answers for one SKU or 404.
+- rest:
+    path: /stock
+    get:
+      - to:
+          uri: direct:all-stock
+      - path: "/{sku}"
+        to:
+          uri: direct:one-sku
+
+- route:
+    id: all-stock
+    from:
+      uri: direct
+      parameters:
+        name: all-stock
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: resource:file:stock.json
+        - setHeader:
+            name: Content-Type
+            expression:
+              constant:
+                expression: application/json
+
+- route:
+    id: one-sku
+    from:
+      uri: direct
+      parameters:
+        name: one-sku
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: resource:file:stock.json
+        - setBody:
+            expression:
+              jsonpath:
+                expression: "$[?(@.sku == '${header.sku}')]"
+                resultType: java.util.List
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body.size()} == 0"
+                steps:
+                  - setHeader:
+                      name: CamelHttpResponseCode
+                      expression:
+                        constant:
+                          expression: "404"
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: '{"error": "unknown sku ${header.sku}"}'
+            otherwise:
+              steps:
+                - setBody:
+                    expression:
+                      simple:
+                        expression: "${body[0]}"
+                - marshal:
+                    json:
+                      library: Jackson
+        - setHeader:
+            name: Content-Type
+            expression:
+              constant:
+                expression: application/json
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock.json
new file mode 100644
index 000000000000..efab5de3aa66
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/connect/stock-api/stock.json
@@ -0,0 +1,5 @@
+[
+  {"sku": "CAMEL-TSHIRT", "qty": 120},
+  {"sku": "CAMEL-MUG", "qty": 42},
+  {"sku": "CAMEL-CAP", "qty": 0}
+]
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/README.md
new file mode 100644
index 000000000000..bee062478acc
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/README.md
@@ -0,0 +1,86 @@
+# OpenAPI client
+
+The picking desk reserves the stock for every order line by calling the stock API by contract: `stock-api.json`
+says which operations exist and how to call them, and the `rest-openapi` component turns an `operationId` into
+the HTTP request. The server is the `openapi-server` example, running in another terminal.
+
+## What you will see
+
+```text
+INFO ... openapi-client.camel.yaml:63 : ORD-1001: reserved 2 x CAMEL-TSHIRT, 120 left on the shelf
+INFO ... openapi-client.camel.yaml:63 : ORD-1001: reserved 1 x CAMEL-MUG, 42 left on the shelf
+INFO ... openapi-client.camel.yaml:63 : ORD-1002: reserved 3 x CAMEL-MUG, 42 left on the shelf
+INFO ... openapi-client.camel.yaml:63 : ORD-1003: reserved 1 x CAMEL-TSHIRT, 120 left on the shelf
+WARN ... openapi-client.camel.yaml:13 : ORD-1003: CAMEL-CAP not reserved, the stock API answered 409: {"error": "only 0 CAMEL-CAP in stock, 1 wanted for ORD-1003"}
+INFO ... openapi-client.camel.yaml:63 : ORD-1003: reserved 2 x CAMEL-MUG, 42 left on the shelf
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+Start the server first, in the `openapi-server` directory:
+
+```shell
+camel run *
+```
+
+Then, in this directory:
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run
+can be repeated. `stock.api.url` in `application.properties` says where the server is.
+
+## How it works
+
+- `rest-openapi` with `specificationUri: stock-api.json` and `operationId: reserveStock` is the call: the
+  component reads the verb, the path and the parameters from the contract, so the route never spells out
+  `POST /api/stock/{sku}/reserve`. `host` is the server; `componentName: http` picks the HTTP client to use.
+- The path parameter `sku` is taken from the header of the same name; the request body is the message body,
+  built here as the JSON the contract's `Reservation` schema describes.
+- The order id and SKU are also kept in exchange properties for the log, since the response replaces the body
+  and headers are sent on the wire, as the `http-client` example explains.
+- A 409 or 400 from the server is an `HttpOperationFailedException`; the `onException` logs its status code
+  and response body and continues with the next line.
+
+## Build it step by step
+
+1. A timer route that calls `rest-openapi` with `operationId: getStock` and a fixed `sku` header; log the body.
+2. Read the orders, split the lines, and call `reserveStock` with the reservation as the body.
+3. Keep the order id and SKU in properties and log the result.
+4. Add the `onException` and see the cap's 409 handled instead of failing the order.
+
+## Try changing
+
+- Set `requestValidationEnabled: true` on the endpoint and send a reservation without `qty`: the client
+  refuses it before any HTTP call.
+- Point `stock.api.url` at a server that is not running and watch the connection error reach the error handler.
+- Replace the contract's server with a public one, `https://petstore3.swagger.io/api/v3/openapi.json`, and
+  call `getPetById`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/openapi-client.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/openapi-client.citrus.it.yaml
+```
+
+The test starts the `openapi-server` example and this client, and verifies the reservations and the 409.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/application.properties
new file mode 100644
index 000000000000..cfc23ac075c7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/application.properties
@@ -0,0 +1,18 @@
+# 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.
+
+stock.api.url=http://localhost:8080
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/openapi-client.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/openapi-client.camel.yaml
new file mode 100644
index 000000000000..f45644fce446
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/openapi-client.camel.yaml
@@ -0,0 +1,64 @@
+# The picking desk reserves the stock for every order line by calling the
+# stock API by contract: stock-api.json says which operations exist and how
+# to call them, and rest-openapi turns an operationId into the HTTP call.
+# The server is the openapi-server example, running in another terminal.
+- onException:
+    exception:
+      - org.apache.camel.http.base.HttpOperationFailedException
+    handled:
+      constant:
+        expression: "true"
+    steps:
+      - log:
+          loggingLevel: WARN
+          message: "${exchangeProperty.orderId}: ${exchangeProperty.sku} not reserved, the stock API answered ${exception.statusCode}: ${exception.responseBody}"
+
+- route:
+    id: reserve-order-lines
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - setProperty:
+            name: orderId
+            expression:
+              simple:
+                expression: "${body[orderId]}"
+        - split:
+            expression:
+              simple:
+                expression: "${body[lines]}"
+            steps:
+              - setProperty:
+                  name: sku
+                  expression:
+                    simple:
+                      expression: "${body[sku]}"
+              # the path parameter comes from the header of the same name
+              - setHeader:
+                  name: sku
+                  expression:
+                    simple:
+                      expression: "${body[sku]}"
+              - setBody:
+                  expression:
+                    simple:
+                      expression: '{"orderId": "${exchangeProperty.orderId}", "qty": ${body[qty]}}'
+              - to:
+                  uri: rest-openapi
+                  parameters:
+                    specificationUri: stock-api.json
+                    operationId: reserveStock
+                    host: "{{stock.api.url}}"
+                    componentName: http
+              - unmarshal:
+                  json:
+                    library: Jackson
+              - log:
+                  message: "${exchangeProperty.orderId}: reserved ${body[reserved]} x ${body[sku]}, ${body[remaining]} left on the shelf"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/stock-api.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/stock-api.json
new file mode 100644
index 000000000000..279b68124da7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-client/stock-api.json
@@ -0,0 +1,201 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "Stock API",
+    "description": "What the warehouse has on the shelf, per SKU, and reservations against it.",
+    "version": "1.0.0"
+  },
+  "servers": [
+    {
+      "url": "http://localhost:8080/api"
+    }
+  ],
+  "paths": {
+    "/stock": {
+      "get": {
+        "operationId": "listStock",
+        "summary": "All stock levels",
+        "responses": {
+          "200": {
+            "description": "The stock levels",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/StockItem"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/stock/{sku}": {
+      "get": {
+        "operationId": "getStock",
+        "summary": "Stock level of one SKU",
+        "parameters": [
+          {
+            "name": "sku",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "The stock level",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/StockItem"
+                }
+              }
+            }
+          },
+          "404": {
+            "description": "Unknown SKU",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/stock/{sku}/reserve": {
+      "post": {
+        "operationId": "reserveStock",
+        "summary": "Reserve a quantity of one SKU for an order",
+        "parameters": [
+          {
+            "name": "sku",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/Reservation"
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "Reserved",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ReservationResult"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "The request does not match the contract"
+          },
+          "404": {
+            "description": "Unknown SKU",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          },
+          "409": {
+            "description": "Not enough stock",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "StockItem": {
+        "type": "object",
+        "required": [
+          "sku",
+          "qty"
+        ],
+        "properties": {
+          "sku": {
+            "type": "string"
+          },
+          "qty": {
+            "type": "integer",
+            "minimum": 0
+          }
+        }
+      },
+      "Reservation": {
+        "type": "object",
+        "required": [
+          "orderId",
+          "qty"
+        ],
+        "properties": {
+          "orderId": {
+            "type": "string"
+          },
+          "qty": {
+            "type": "integer",
+            "minimum": 1
+          }
+        }
+      },
+      "ReservationResult": {
+        "type": "object",
+        "required": [
+          "sku",
+          "reserved",
+          "remaining"
+        ],
+        "properties": {
+          "sku": {
+            "type": "string"
+          },
+          "reserved": {
+            "type": "integer"
+          },
+          "remaining": {
+            "type": "integer"
+          }
+        }
+      },
+      "Error": {
+        "type": "object",
+        "required": [
+          "error"
+        ],
+        "properties": {
+          "error": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/README.md
new file mode 100644
index 000000000000..04fbb1092666
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/README.md
@@ -0,0 +1,91 @@
+# OpenAPI server
+
+The stock API, contract first. `stock-api.json` is the OpenAPI contract: three operations, their parameters,
+request and response schemas and status codes. The REST DSL serves every operation in it, validates requests
+against it and hands each operation to a `direct` route named after its `operationId`.
+
+## What you will see
+
+```text
+$ curl localhost:8080/api/stock/CAMEL-MUG
+{"sku":"CAMEL-MUG","qty":42}
+
+$ curl -X POST -H 'Content-Type: application/json' -d '{"orderId": "ORD-1001", "qty": 2}' localhost:8080/api/stock/CAMEL-MUG/reserve
+{"sku": "CAMEL-MUG", "reserved": 2, "remaining": 42}
+
+$ curl -i -X POST -H 'Content-Type: application/json' -d '{"orderId": "ORD-1003", "qty": 1}' localhost:8080/api/stock/CAMEL-CAP/reserve
+HTTP/1.1 409 Conflict
+{"error": "only 0 CAMEL-CAP in stock, 1 wanted for ORD-1003"}
+
+$ curl -i -X POST -H 'Content-Type: application/json' localhost:8080/api/stock/CAMEL-MUG/reserve
+HTTP/1.1 400 Bad Request
+
+INFO ... openapi-server.camel.yaml:123 : Reserved 2 x CAMEL-MUG for ORD-1001
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The contract's `servers` entry gives the base path, `/api`, so the operations are under http://localhost:8080/api/stock
+and the contract itself is served at http://localhost:8080/openapi. Call the
+operations with `curl` as above from another terminal, or run the `openapi-client` example against it.
+Stop it with `ctrl` + `c`.
+
+## How it works
+
+- `rest` with `openApi: specification: stock-api.json` is the whole API definition: paths, verbs and parameters
+  come from the contract, not from the route file, and the base path `/api` from its `servers` entry, which
+  must have a path. `restConfiguration` switches on `clientRequestValidation`,
+  which rejects a request without the body or content type the contract requires with 400, and
+  `apiContextPath: openapi` serves the contract.
+- Each operation is a `direct` route named after its `operationId`: `listStock`, `getStock`, `reserveStock`.
+  Path parameters arrive as headers, `sku` here; the request body is the message body.
+- `lookup` is a helper route the two SKU operations share: it filters the stock file with `jsonpath` and
+  leaves the item, or null, as the body.
+- The contract check does not look at the values, so `reserveStock` runs `validate` on them and an
+  `onException` turns the failed predicate into a 400 with an error body, the status the contract promises.
+- `CamelHttpResponseCode` sets 404 and 409; the bodies are the JSON the contract's `Error` schema describes.
+
+## Build it step by step
+
+1. Write `stock-api.json` with only `listStock`, add the `rest` block and a `listStock` route that returns
+   `resource:file:stock.json`; run it and open http://localhost:8080/openapi.
+2. Add `getStock` to the contract and the route, with the `lookup` helper and the 404.
+3. Add `reserveStock` with its request schema; POST without a body and see the 400 from the contract check.
+4. Add `validate` and the `onException` for the values, then the 409 for short stock.
+
+## Try changing
+
+- Add a fourth operation to the contract and start the example: the missing route is reported at startup.
+- Set `missingOperation: mock` in `restConfiguration` and put an example response under `examples/`: the
+  operation is served from the example without a route.
+- Change a response schema in the contract and see what the client example makes of it.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/openapi-server.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/openapi-server.citrus.it.yaml
+```
+
+The test starts the API and calls the three operations over HTTP, checking the 200, 409 and 400 answers.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/application.properties
new file mode 100644
index 000000000000..5d54c44f16dc
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/application.properties
@@ -0,0 +1,18 @@
+# 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.
+
+camel.server.port=8080
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/openapi-server.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/openapi-server.camel.yaml
new file mode 100644
index 000000000000..23d364e09707
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/openapi-server.camel.yaml
@@ -0,0 +1,162 @@
+# The stock API, contract first: stock-api.json is the OpenAPI contract, the
+# REST DSL serves every operation in it, requests are validated against it,
+# and each operation is a direct route named after its operationId.
+- restConfiguration:
+    clientRequestValidation: true
+    apiContextPath: openapi
+
+# The contract check rejects a missing body or a wrong content type; the values are the route's job
+- onException:
+    exception:
+      - org.apache.camel.support.processor.PredicateValidationException
+    handled:
+      constant:
+        expression: "true"
+    steps:
+      - setHeader:
+          name: CamelHttpResponseCode
+          expression:
+            constant:
+              expression: "400"
+      - setBody:
+          expression:
+            simple:
+              expression: '{"error": "orderId and a positive qty are required"}'
+
+- rest:
+    openApi:
+      specification: stock-api.json
+
+- route:
+    id: listStock
+    from:
+      uri: direct
+      parameters:
+        name: listStock
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: resource:file:stock.json
+
+- route:
+    id: getStock
+    from:
+      uri: direct
+      parameters:
+        name: getStock
+      steps:
+        - to:
+            uri: direct:lookup
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body} == null"
+                steps:
+                  - setHeader:
+                      name: CamelHttpResponseCode
+                      expression:
+                        constant:
+                          expression: "404"
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: '{"error": "unknown sku ${header.sku}"}'
+            otherwise:
+              steps:
+                - marshal:
+                    json:
+                      library: Jackson
+
+- route:
+    id: reserveStock
+    from:
+      uri: direct
+      parameters:
+        name: reserveStock
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - validate:
+            expression:
+              simple:
+                expression: "${body[orderId]} != null && ${body[qty]} > 0"
+        - setProperty:
+            name: reservation
+            expression:
+              simple:
+                expression: "${body}"
+        - to:
+            uri: direct:lookup
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body} == null"
+                steps:
+                  - setHeader:
+                      name: CamelHttpResponseCode
+                      expression:
+                        constant:
+                          expression: "404"
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: '{"error": "unknown sku ${header.sku}"}'
+              - expression:
+                  simple:
+                    expression: "${body[qty]} < ${exchangeProperty.reservation[qty]}"
+                steps:
+                  - setHeader:
+                      name: CamelHttpResponseCode
+                      expression:
+                        constant:
+                          expression: "409"
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: '{"error": "only ${body[qty]} ${header.sku} in stock, ${exchangeProperty.reservation[qty]} wanted for ${exchangeProperty.reservation[orderId]}"}'
+            otherwise:
+              steps:
+                - log:
+                    message: "Reserved ${exchangeProperty.reservation[qty]} x ${header.sku} for ${exchangeProperty.reservation[orderId]}"
+                - setBody:
+                    expression:
+                      simple:
+                        expression: '{"sku": "${header.sku}", "reserved": ${exchangeProperty.reservation[qty]}, "remaining": ${body[qty]}}'
+
+# Finds one SKU in the stock file: the item as a map, or null
+- route:
+    id: lookup
+    from:
+      uri: direct
+      parameters:
+        name: lookup
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: resource:file:stock.json
+        - setBody:
+            expression:
+              jsonpath:
+                expression: "$[?(@.sku == '${header.sku}')]"
+                resultType: java.util.List
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body.size()} == 0"
+                steps:
+                  - setBody:
+                      expression:
+                        simple:
+                          expression: "${null}"
+            otherwise:
+              steps:
+                - setBody:
+                    expression:
+                      simple:
+                        expression: "${body[0]}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock-api.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock-api.json
new file mode 100644
index 000000000000..279b68124da7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock-api.json
@@ -0,0 +1,201 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "Stock API",
+    "description": "What the warehouse has on the shelf, per SKU, and reservations against it.",
+    "version": "1.0.0"
+  },
+  "servers": [
+    {
+      "url": "http://localhost:8080/api"
+    }
+  ],
+  "paths": {
+    "/stock": {
+      "get": {
+        "operationId": "listStock",
+        "summary": "All stock levels",
+        "responses": {
+          "200": {
+            "description": "The stock levels",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/StockItem"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/stock/{sku}": {
+      "get": {
+        "operationId": "getStock",
+        "summary": "Stock level of one SKU",
+        "parameters": [
+          {
+            "name": "sku",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "The stock level",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/StockItem"
+                }
+              }
+            }
+          },
+          "404": {
+            "description": "Unknown SKU",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/stock/{sku}/reserve": {
+      "post": {
+        "operationId": "reserveStock",
+        "summary": "Reserve a quantity of one SKU for an order",
+        "parameters": [
+          {
+            "name": "sku",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/Reservation"
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "Reserved",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ReservationResult"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "The request does not match the contract"
+          },
+          "404": {
+            "description": "Unknown SKU",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          },
+          "409": {
+            "description": "Not enough stock",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "StockItem": {
+        "type": "object",
+        "required": [
+          "sku",
+          "qty"
+        ],
+        "properties": {
+          "sku": {
+            "type": "string"
+          },
+          "qty": {
+            "type": "integer",
+            "minimum": 0
+          }
+        }
+      },
+      "Reservation": {
+        "type": "object",
+        "required": [
+          "orderId",
+          "qty"
+        ],
+        "properties": {
+          "orderId": {
+            "type": "string"
+          },
+          "qty": {
+            "type": "integer",
+            "minimum": 1
+          }
+        }
+      },
+      "ReservationResult": {
+        "type": "object",
+        "required": [
+          "sku",
+          "reserved",
+          "remaining"
+        ],
+        "properties": {
+          "sku": {
+            "type": "string"
+          },
+          "reserved": {
+            "type": "integer"
+          },
+          "remaining": {
+            "type": "integer"
+          }
+        }
+      },
+      "Error": {
+        "type": "object",
+        "required": [
+          "error"
+        ],
+        "properties": {
+          "error": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock.json
new file mode 100644
index 000000000000..efab5de3aa66
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/contracts/openapi-server/stock.json
@@ -0,0 +1,5 @@
+[
+  {"sku": "CAMEL-TSHIRT", "qty": 120},
+  {"sku": "CAMEL-MUG", "qty": 42},
+  {"sku": "CAMEL-CAP", "qty": 0}
+]
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/circuit-breaker/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/circuit-breaker/README.md
index f2a99ddcb55d..c38d1596fe7e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/circuit-breaker/README.md
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/circuit-breaker/README.md
@@ -19,7 +19,8 @@ INFO ... circuit-breaker.camel.yaml:30 : Stock check 15 (breaker CLOSED): CAMEL-
 
 ## Install Camel CLI
 
-<!-- see installation instructions in ../../install.adoc -->
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
 
 ## Run it
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/README.md
new file mode 100644
index 000000000000..00b24b2a213f
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/README.md
@@ -0,0 +1,82 @@
+# Error handling
+
+Three orders go to the payment provider. One is charged at once. For one the provider does not answer, twice,
+and the error handler retries until it does. One card is declined, which no retry will fix, so the order is
+parked as a file for someone to look at.
+
+## What you will see
+
+```text
+INFO ... error-handling.camel.yaml:40 : Payment for ORD-1001 charged, 2 line(s) to the warehouse
+WARN ... DeadLetterChannel : Failed delivery for (...). On delivery attempt: 0 caught: java.net.ConnectException: payment provider did not answer
+WARN ... DeadLetterChannel : Failed delivery for (...). On delivery attempt: 1 caught: java.net.ConnectException: payment provider did not answer
+INFO ... error-handling.camel.yaml:40 : Payment for ORD-1002 charged, 1 line(s) to the warehouse
+INFO ... error-handling.camel.yaml:21 : Payment for ORD-1003 declined: card declined
+INFO ... error-handling.camel.yaml:75 : Order ORD-1003 parked for manual review: card declined
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place). The declined order
+ends up in `parked/order-1003.json`.
+
+## How it works
+
+- `errorHandler` with `deadLetterChannel` is the default for every route in the file: a failure is retried twice
+  with a second in between (`redeliveryPolicy`), each attempt logged at WARN, and when the retries are used up the
+  message goes to the dead letter uri, `direct:parked`, and counts as handled.
+- `onException` for `IllegalStateException`, the declined card, overrides that for one exception type: no
+  retries, `handled` so the file consumer is done with the order, and its own steps log and park it.
+- The payment provider is its own route with `noErrorHandler`, so its exceptions reach the caller and the retry
+  repeats the whole `to: direct:charge` call, as it would for a remote service. Camel retries the step that
+  failed, and a step that always throws would always fail; the provider answers on the third attempt because it
+  reads `CamelRedeliveryCounter`.
+- The parked route can use `${exception.message}` because the error handler keeps the exception on the exchange.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order, calls `direct:charge` and logs the payment; a second
+   route from `direct:charge` that throws for ORD-1003. Without any error handler the failure is logged with a
+   stack trace and the order is dropped.
+2. Add `errorHandler` with `deadLetterChannel` to `direct:parked` and a route that logs there. The stack
+   trace is gone and the order is parked, after three attempts a second apart.
+3. Add `noErrorHandler` to the provider route and make it throw `ConnectException` for ORD-1002 unless
+   `CamelRedeliveryCounter` is 2: two warnings, then charged.
+4. Add the `onException` for the declined card with no retries.
+
+## Try changing
+
+- Raise `maximumRedeliveries` to 5 with `backOffMultiplier: 2` and `useExponentialBackOff: true` and watch the
+  delays grow.
+- Replace `direct:parked` with a file endpoint straight in `deadLetterUri` and drop the parked route.
+- Make the provider fail for every order and see all three parked.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/error-handling.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/error-handling.citrus.it.yaml
+```
+
+The test starts the route and verifies the charged, declined and parked lines.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/error-handling.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/error-handling.camel.yaml
new file mode 100644
index 000000000000..8d9f00600110
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/error-handling.camel.yaml
@@ -0,0 +1,84 @@
+# Payment for the web shop orders. The payment provider is flaky for one order
+# and declines another; the error handler retries the first and parks both.
+- errorHandler:
+    deadLetterChannel:
+      deadLetterUri: direct:parked
+      redeliveryPolicy:
+        maximumRedeliveries: 2
+        redeliveryDelay: 1000
+        retryAttemptedLogLevel: WARN
+
+# A declined card is final: no retry, park it at once
+- onException:
+    exception:
+      - java.lang.IllegalStateException
+    redeliveryPolicy:
+      maximumRedeliveries: 0
+    handled:
+      constant:
+        expression: "true"
+    steps:
+      - log:
+          message: "Payment for ${body[orderId]} declined: ${exception.message}"
+      - to:
+          uri: direct:parked
+
+- route:
+    id: checkout
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - to:
+            uri: direct:charge
+        - log:
+            message: "Payment for ${body[orderId]} charged, ${body[lines].size()} line(s) to the warehouse"
+
+# The payment provider. No error handler here, so its failures reach the caller,
+# which retries the whole call as it would with a remote service.
+- route:
+    id: payment-provider
+    errorHandler:
+      noErrorHandler: {}
+    from:
+      uri: direct:charge
+      steps:
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body[orderId]} == 'ORD-1002' && ${header.CamelRedeliveryCounter} != 2"
+                steps:
+                  - throwException:
+                      exceptionType: java.net.ConnectException
+                      message: "payment provider did not answer"
+              - expression:
+                  simple:
+                    expression: "${body[orderId]} == 'ORD-1003'"
+                steps:
+                  - throwException:
+                      exceptionType: java.lang.IllegalStateException
+                      message: "card declined"
+
+# Parked orders are written as files for someone to look at
+- route:
+    id: parked
+    from:
+      uri: direct:parked
+      steps:
+        - log:
+            message: "Order ${body[orderId]} parked for manual review: ${exception.message}"
+        - marshal:
+            json:
+              library: Jackson
+        - to:
+            uri: file
+            parameters:
+              directoryName: parked
+              fileName: "${header.CamelFileName}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/fail-well/error-handling/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/README.md
index db3dac32b83c..2fc82eea0e84 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/README.md
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/README.md
@@ -1,12 +1,73 @@
-## REST API
+# REST API
 
-This example shows a REST API with hello endpoints.
+A REST API on port 8080, served by the HTTP server built into the Camel CLI: `GET /api/hello` answers the
+greeting from `application.properties` and `GET /api/hello/{name}` answers a greeting with the name.
 
-### How to run
+## What you will see
 
-    camel run rest-api.camel.yaml
+```text
+$ curl localhost:8080/api/hello
+Hello from Camel REST API!
 
-### Try it
+$ curl localhost:8080/api/hello/World
+Hello World from Camel REST API!
+```
 
-    curl http://localhost:8080/api/hello
-    curl http://localhost:8080/api/hello/World
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+Then, in another terminal, call it with `curl` as above. Stop it with `ctrl` + `c`.
+
+## How it works
+
+- `rest-api.camel.yaml` declares the API with the REST DSL: a `rest` with `path: /api` and two `get`
+  operations, `/hello` and `/hello/{name}`. Each operation hands over to a `direct` route with `to`.
+- The two `direct` routes set the body that becomes the HTTP response: a constant with the greeting from
+  `application.properties`, and a simple expression in which the `{name}` path parameter arrives as the
+  header `name`.
+- The CLI starts the HTTP server because the file uses the REST DSL; `camel.server.port` in
+  `application.properties` sets the port.
+
+## Build it step by step
+
+Ask your assistant, or type it yourself, one step at a time, and run after each:
+
+1. A `rest` with `path: /api` and one `get` on `/hello` that goes to a direct route answering "Hello";
+   run it and `curl localhost:8080/api/hello`.
+2. Add the `/hello/{name}` operation and a second direct route that answers with `${header.name}`.
+3. Move the greeting and the port to `application.properties`.
+
+## Try changing
+
+- Add `POST /api/hello` that answers with the request body: `curl -d 'Camel' localhost:8080/api/hello`.
+- Set the header `Content-Type` to `application/json` and answer `{"greeting": "${body}"}`.
+- Run with `--console` and open http://localhost:8080/q/dev to see the routes and their statistics.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/rest-api.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/rest-api.citrus.it.yaml
+```
+
+The test starts the route and calls both operations over HTTP.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/application.properties
index f3ee4076eb17..4abd98e0127a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/application.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/rest-api/application.properties
@@ -1,3 +1,20 @@
+# 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.
+
 # HTTP server port
 camel.server.port=8080
 # Greeting message for the hello endpoint
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/Greeter.java b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/Greeter.java
index bdb9a45ec3a6..605356270bcf 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/Greeter.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/Greeter.java
@@ -1,20 +1,34 @@
+/*
+ * 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.
+ */
 package camel.example;
 
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+/**
+ * Builds the greeting. A plain Java class next to the route, with no Camel API in it: beans.yaml declares it as the
+ * bean greeter and sets its greeting from a property, and the route calls its greet method with the message body.
+ */
+public class Greeter {
 
-public class Greeter implements Processor {
+    private String greeting;
 
-    private String message;
-
-    public void setMessage(String message) {
-        this.message = message;
+    public void setGreeting(String greeting) {
+        this.greeting = greeting;
     }
 
-    @Override
-    public void process(Exchange exchange) throws Exception {
-        String body = exchange.getIn().getBody(String.class);
-        exchange.getIn().setBody(message + " " + body);
+    public String greet(String name) {
+        return greeting + ", " + name + "!";
     }
-
-}
\ No newline at end of file
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/README.md
index 8157bcfa24ed..c8e1d74f6af4 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/README.md
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/README.md
@@ -1,67 +1,68 @@
-## Routes
+# Routes
 
-This example shows how routes are defined in Yaml.
+The first step from YAML into your own code: a timer route in YAML calls a Java bean, `Greeter`, that builds
+the message, and logs what the bean returned.
 
-### Install JBang
+## What you will see
 
-First install JBang according to https://www.jbang.dev
-
-When JBang is installed then you should be able to run from a shell:
-
-```sh
-$ jbang --version
-```
-
-This will output the version of JBang.
-
-To run this example you can either install Camel on JBang via:
-
-```sh
-$ jbang app install camel@apache/camel
+```text
+INFO ... routes.camel.yaml:16 : Hello, Camel!
+INFO ... routes.camel.yaml:16 : Hello, Camel!
 ```
 
-Which allows to run Camel CLI with `camel` as shown below.
+## Install Camel CLI
 
-### How to run
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
 
-You can run this example using:
+## Run it
 
-```sh
-$ camel run *
+```shell
+camel run *
 ```
 
-Camel will start a route that periodically provides a greeting message.
+Stop it with `ctrl` + `c`, or from another terminal with `camel stop routes`.
 
-### Live reload
+## How it works
 
-You can run the example in dev mode which allows you to edit the example,
-and hot-reload when the file is saved.
+- `routes.camel.yaml` is the route: a `timer` fires every second, a `setBody` puts the name `Camel` in the
+  message, a `bean` step calls the `greet` method of the bean `greeter` with the body, and a `log` prints
+  what the method returned, which is now the body.
+- `Greeter.java` is a plain Java class next to the route, with no Camel API in it: a `greeting` property and a
+  `greet(String name)` method. The CLI compiles it when the route starts.
+- `beans.yaml` declares the class as the bean `greeter` and sets its `greeting` from a property.
+- `application.properties` holds the greeting and the timer period.
 
-```sh
-$ camel run * --dev
-```
+## Build it step by step
 
-### Run directly from GitHub
+Ask your assistant, or type it yourself, one step at a time, and run after each:
 
-The example can also be run directly by referring to the GitHub URL as shown:
+1. A route from a timer that sets the body to "Camel" and logs it.
+2. A Java class `Greeter` in the package `camel.example` with a method `greet(String name)` that returns
+   "Hello, " and the name, declared as the bean `greeter` in `beans.yaml`; call it from the route with a
+   `bean` step before the log.
+3. Give the class a `greeting` property, set it in `beans.yaml`, and move its value to
+   `application.properties`.
 
-```sh
-$ camel run https://github.com/apache/camel-jbang-examples/tree/main/routes
-```
+## Try changing
 
-### Developer Web Console
+- `greeter.greeting=Hej` in `application.properties`; the Java class and the route do not change.
+- Add a second method `shout(String name)` that returns the greeting in upper case and switch the `method` in
+  the route.
+- Leave out `method: greet` and see that Camel finds the single public method by itself.
 
-You can enable the developer console via `--console` flag as show:
+## Integration testing
 
-```sh
-$ camel run * --console
-```
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/routes.citrus.it.yaml`, which the Camel CLI runs:
 
-Then you can browse: http://localhost:8080/q/dev to introspect the running Camel Application.
-Under "beans" Camel should display bean `greeter`.
+```shell
+camel test run test/routes.citrus.it.yaml
+```
 
+The test starts the route, with the bean and the Java class, and verifies the logged greeting.
 
-### Help and contributions
+## Help and contributions
 
 If you hit any problem using Camel or have some feedback, then please
 [let us know](https://camel.apache.org/community/support/).
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/application.properties
index 9049d38c3ecf..a6616c43986d 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/application.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/application.properties
@@ -1,2 +1,21 @@
-# Greeting message used by the Greeter bean
-greeter.message=Hello!
+# 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.
+
+# The greeting the Greeter bean starts its message with
+greeter.greeting=Hello
+# How often the timer fires, in milliseconds
+greeter.period=1000
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/beans.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/beans.yaml
index a984e7798770..ec4497028a00 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/beans.yaml
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/beans.yaml
@@ -1,5 +1,5 @@
 - beans:
-  - name: "greeter"
-    type: "camel.example.Greeter"
-    properties:
-      message: '{{greeter.message}}'
+    - name: greeter
+      type: "camel.example.Greeter"
+      properties:
+        greeting: "{{greeter.greeting}}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/routes.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/routes.camel.yaml
index a15415f483a1..76ae52820ca4 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/routes.camel.yaml
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/routes/routes.camel.yaml
@@ -1,17 +1,17 @@
 - route:
-    id: greeting-route
+    id: greeting
     from:
       uri: timer
       parameters:
-        timerName: start
-        period: 1000
+        timerName: greet
+        period: "{{greeter.period}}"
       steps:
         - setBody:
             expression:
-              simple:
-                expression: "I'm ${routeId}"
+              constant:
+                expression: "Camel"
         - bean:
             ref: greeter
+            method: greet
         - log:
             message: "${body}"
-
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/splitter/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/splitter/README.md
index ea673ccfe3aa..a07be02973d6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/splitter/README.md
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/splitter/README.md
@@ -1,42 +1,72 @@
-## Splitter
+# Splitter
 
-This example demonstrates the Splitter EIP.
+A timer creates a comma-separated batch of items, the splitter turns it into one message per item, and each item
+is logged on its own line.
 
-A batch of comma-separated product names is split into individual messages.
-Each item is logged with its split index.
+## What you will see
 
-The splitter processes each part of the message independently, which is useful
-for breaking down bulk data into individual records for downstream processing.
+```text
+INFO ... splitter.camel.yaml:14 : Received batch: Laptop,Phone,Tablet,Monitor,Keyboard
+INFO ... splitter.camel.yaml:21 : Processing item 0: Laptop
+INFO ... splitter.camel.yaml:21 : Processing item 1: Phone
+INFO ... splitter.camel.yaml:21 : Processing item 2: Tablet
+INFO ... splitter.camel.yaml:21 : Processing item 3: Monitor
+INFO ... splitter.camel.yaml:21 : Processing item 4: Keyboard
+```
+
+The batch is sent three times, five seconds apart, and then the timer stops.
 
-### Install JBang
+## Install Camel CLI
 
-First install JBang according to https://www.jbang.dev
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
 
-When JBang is installed then you should be able to run from a shell:
+## Run it
 
-```sh
-$ jbang --version
+```shell
+camel run *
 ```
 
-This will output the version of JBang.
+Stop it with `ctrl` + `c`, or from another terminal with `camel stop splitter`.
 
-To run this example you can either install Camel on JBang via:
+## How it works
 
-```sh
-$ jbang app install camel@apache/camel
-```
+- `splitter.camel.yaml` is the route: a `timer` with `repeatCount: 3` fires three times, a `setBody` puts the
+  batch in the message as one string, and a `log` prints it.
+- `split` with a `tokenize` expression on `,` turns the one message into five, one per item. The steps under
+  the `split` run once for each of them: here a `log` with the item.
+- `CamelSplitIndex` is a header the splitter sets on each part, counting from 0; `CamelSplitSize` is the
+  total and `CamelSplitComplete` is true on the last part.
+- After the last part the route continues after the `split` with the original batch as the body; there is
+  nothing after it here.
+
+## Build it step by step
 
-Which allows to run Camel CLI with `camel` as shown below.
+Ask your assistant, or type it yourself, one step at a time, and run after each:
 
-### How to run
+1. A route from a timer that sets the body to "Laptop,Phone,Tablet" and logs it.
+2. Split the body on the comma and log each part.
+3. Add the split index to the log line, and `repeatCount: 3` to the timer.
 
-You can run this example using:
+## Try changing
 
-```sh
-$ camel run *
+- Log `${header.CamelSplitIndex} of ${header.CamelSplitSize}` on each part.
+- Add a `log` after the `split` and see the original batch come back as the body.
+- Split a JSON array instead: set the body to `["Laptop","Phone"]` and use `jsonpath: {expression: "$[*]"}`
+  as the split expression.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/splitter.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/splitter.citrus.it.yaml
 ```
 
-### Help and contributions
+The test starts the route and verifies the batch and the last item are logged.
+
+## Help and contributions
 
 If you hit any problem using Camel or have some feedback, then please
 [let us know](https://camel.apache.org/community/support/).
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/README.md
index f773ce1bad55..5b44f204ef82 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/README.md
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/README.md
@@ -1,7 +1,69 @@
-## Timer Log
+# Timer Log
 
-This example shows a simple timer that logs a hello message every second.
+The hello of Camel in one file: a timer fires every second and a log line prints the greeting from
+`application.properties`.
 
-### How to run
+## What you will see
 
-    camel run timer-log.camel.yaml
+```text
+INFO ... timer-log.camel.yaml:13 : Hello Camel!
+INFO ... timer-log.camel.yaml:13 : Hello Camel!
+INFO ... timer-log.camel.yaml:13 : Hello Camel!
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+Stop it with `ctrl` + `c`, or from another terminal with `camel stop timer-log`.
+
+## How it works
+
+- `timer-log.camel.yaml` is the route: `from` a `timer` that fires every `timer.period` milliseconds, a
+  `setBody` puts the greeting in the message, and a `log` prints the body.
+- `application.properties` holds the period and the greeting. `{{timer.period}}` and `{{greeting.message}}`
+  in the route are property placeholders, resolved when the route starts.
+- The Camel CLI reads every file in the directory: the route because it ends in `.camel.yaml`, the properties
+  because of their name.
+
+## Build it step by step
+
+Ask your assistant, or type it yourself, one step at a time, and run after each:
+
+1. A route from a timer that logs "Hello Camel!" every second.
+2. Move the greeting to `application.properties` and set the body from the property.
+3. Move the period to a property too.
+
+## Try changing
+
+- `timer.period=5000` for a greeting every five seconds; the route file does not change.
+- Add `repeatCount: 3` to the timer parameters and the timer stops after three greetings.
+- Log `${date:now:HH:mm:ss} ${body}` to see when each line was written.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/timer-log.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/timer-log.citrus.it.yaml
+```
+
+The test starts the route and verifies the logged greeting.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/application.properties
index 370577aacb69..5cc0a54df8e4 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/application.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/quick-start/timer-log/application.properties
@@ -1,3 +1,20 @@
+# 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.
+
 # Timer period in milliseconds
 timer.period=1000
 # Greeting message to log
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/README.md
new file mode 100644
index 000000000000..56789ff9d1e1
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/README.md
@@ -0,0 +1,73 @@
+# Aggregator
+
+The reverse of `order-lines`: the warehouse reports each picked line on its own, and the aggregator collects the
+lines of one order back into a shipment. Lines are correlated by the order id, and a shipment completes when all
+the lines the order had are in.
+
+## What you will see
+
+```text
+INFO ... aggregator.camel.yaml:26 : Picked 2 x CAMEL-TSHIRT for ORD-1001
+INFO ... aggregator.camel.yaml:26 : Picked 1 x CAMEL-MUG for ORD-1001
+INFO ... aggregator.camel.yaml:26 : Picked 3 x CAMEL-MUG for ORD-1002
+...
+INFO ... aggregator.camel.yaml:51 : Shipment for ORD-1001 complete: [{"sku":"CAMEL-TSHIRT","qty":2,"price":19.95},{"sku":"CAMEL-MUG","qty":1,"price":9.5}]
+INFO ... aggregator.camel.yaml:51 : Shipment for ORD-1002 complete: [{"sku":"CAMEL-MUG","qty":3,"price":9.5}]
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run
+can be repeated.
+
+## How it works
+
+- The first route reads the orders, keeps the order id in a header, splits them into lines, and sends every
+  line to `direct:shipment`, as a warehouse system would report picks one by one.
+- The second route aggregates: `correlationExpression` `${header.orderId}` groups lines of the same order,
+  `completionSizeExpression` `${header.CamelSplitSize}` says how many lines make the order complete, and the
+  `GroupedBodyAggregationStrategy` collects the bodies into a list.
+- When a shipment completes, the list of lines is written as JSON with `marshal` and logged.
+
+## Build it step by step
+
+1. Start from `order-lines` and send each line to `direct:shipment` instead of only logging it.
+2. Add a route from `direct:shipment` with an `aggregate` correlating on `${header.orderId}` and a fixed
+   `completionSize: 2`; only the two-line order completes.
+3. Replace the fixed size by `completionSizeExpression` with `${header.CamelSplitSize}`.
+4. Add `marshal` with `json` and log the shipment.
+
+## Try changing
+
+- Add `completionTimeout: 5000` so a shipment with a missing line still closes after five seconds.
+- Sum the pieces instead of listing the lines: the `data-mapping` example shows the Groovy for it.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/aggregator.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/aggregator.citrus.it.yaml
+```
+
+The test starts the route and verifies that the shipments for the three orders complete.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/aggregator.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/aggregator.camel.yaml
new file mode 100644
index 000000000000..5148ba54b6b8
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/aggregator.camel.yaml
@@ -0,0 +1,52 @@
+# The reverse of order-lines: the warehouse reports each picked line on its own, and the aggregator
+# collects the lines of one order back into a shipment. Lines are correlated by the order id, and a
+# shipment completes when all the lines the order had are in.
+- route:
+    id: picked-lines
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - setHeader:
+            name: orderId
+            expression:
+              simple:
+                expression: "${body[orderId]}"
+        - split:
+            expression:
+              simple:
+                expression: "${body[lines]}"
+            steps:
+              - log:
+                  message: "Picked ${body[qty]} x ${body[sku]} for ${header.orderId}"
+              - to:
+                  uri: direct
+                  parameters:
+                    name: shipment
+- route:
+    id: aggregator
+    from:
+      uri: direct
+      parameters:
+        name: shipment
+      steps:
+        - aggregate:
+            aggregationStrategy: "#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+            correlationExpression:
+              simple:
+                expression: "${header.orderId}"
+            completionSizeExpression:
+              simple:
+                expression: "${header.CamelSplitSize}"
+            steps:
+              - marshal:
+                  json:
+                    library: Jackson
+              - log:
+                  message: "Shipment for ${header.orderId} complete: ${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/aggregator/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/README.md
new file mode 100644
index 000000000000..4bbb6390c7ff
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/README.md
@@ -0,0 +1,67 @@
+# Content-based router
+
+Three orders from three countries. A `choice` routes each by its country: the Danish order to local delivery,
+EU orders to shipping without customs, everything else to export with a customs declaration.
+
+## What you will see
+
+```text
+INFO ... content-based-router.camel.yaml:22 : Order ORD-1001 from DK: local delivery from the Copenhagen warehouse
+INFO ... content-based-router.camel.yaml:28 : Order ORD-1002 from DE: EU shipping, no customs
+INFO ... content-based-router.camel.yaml:32 : Order ORD-1003 from US: export, customs declaration needed
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run
+can be repeated.
+
+## How it works
+
+- The `file` consumer reads the three orders from `orders/` in name order; `unmarshal` with `json` parses each,
+  so `${body[country]}` reads a field.
+- `choice` tests the country: `== 'DK'` first, then `in 'DE,SE,NL,FR'`, the simple language's list test, and
+  `otherwise` takes the rest. The first matching `when` wins.
+- Each branch only logs here; in a real shop each `to:` a different route or system.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs `${body[orderId]}` and `${body[country]}`.
+2. Add a `choice` with one `when` for `DK` and an `otherwise`, each logging a different line.
+3. Add a second `when` for the EU countries with `in 'DE,SE,NL,FR'`.
+4. Add a fourth order file for a Swedish customer and see it take the EU branch.
+
+## Try changing
+
+- Route on the order value instead: `${body[lines].size()} > 2` for big orders.
+- Replace the logs with `to: direct:...` routes, one per branch, as `filter-and-multicast` does.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/content-based-router.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/content-based-router.citrus.it.yaml
+```
+
+The test starts the route and verifies that each of the three orders is logged from its branch.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/content-based-router.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/content-based-router.camel.yaml
new file mode 100644
index 000000000000..017afeea9279
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/content-based-router.camel.yaml
@@ -0,0 +1,33 @@
+# Three orders from three countries. A choice routes each by its country: Danish orders go to the
+# local warehouse, EU orders ship without customs, everything else is an export with a customs
+# declaration. Each branch logs what it did.
+- route:
+    id: content-based-router
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: "${body[country]} == 'DK'"
+                steps:
+                  - log:
+                      message: "Order ${body[orderId]} from ${body[country]}: local delivery from the Copenhagen warehouse"
+              - expression:
+                  simple:
+                    expression: "${body[country]} in 'DE,SE,NL,FR'"
+                steps:
+                  - log:
+                      message: "Order ${body[orderId]} from ${body[country]}: EU shipping, no customs"
+            otherwise:
+              steps:
+                - log:
+                    message: "Order ${body[orderId]} from ${body[country]}: export, customs declaration needed"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/content-based-router/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/README.md
new file mode 100644
index 000000000000..fd45f5348091
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/README.md
@@ -0,0 +1,69 @@
+# Filter and multicast
+
+Only paid orders go further, and a paid order goes to two places at once: the warehouse to pick it and invoicing
+to bill it. The `filter` drops the unpaid order; the `multicast` sends the same message to both routes.
+
+## What you will see
+
+```text
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1001 received, status paid
+INFO ... filter-and-multicast.camel.yaml:40 : Warehouse: pick 2 line(s) for ORD-1001
+INFO ... filter-and-multicast.camel.yaml:49 : Invoicing: bill customer C-482 for ORD-1001
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1002 received, status paid
+...
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1003 received, status pending
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run
+can be repeated.
+
+## How it works
+
+- `filter` with `${body[status]} == 'paid'` lets paid orders into its steps; the pending order is logged as
+  received and goes no further, which is the difference from `choice`: a filter has no otherwise.
+- `multicast` sends a copy of the message to each `to:` in turn, `direct:warehouse` then `direct:invoicing`.
+- The two `direct` routes are the two departments; each logs its part of the work.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs its id and status.
+2. Add a `filter` on the status and log inside it; the pending order disappears from the inner log.
+3. Add `direct:warehouse` and `direct:invoicing` routes and a `multicast` to both inside the filter.
+4. Add `parallelProcessing: true` to the multicast and see both departments log at the same moment.
+
+## Try changing
+
+- Add a third department, `direct:analytics`, that logs the order total.
+- Use `recipientList` with a header listing the departments instead of a fixed `multicast`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/filter-and-multicast.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/filter-and-multicast.citrus.it.yaml
+```
+
+The test starts the route and verifies that the warehouse and invoicing logs appear for the paid orders.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/filter-and-multicast.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/filter-and-multicast.camel.yaml
new file mode 100644
index 000000000000..1559e2bb1333
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/filter-and-multicast.camel.yaml
@@ -0,0 +1,50 @@
+# Only paid orders go further, and a paid order goes to two places at once: the warehouse to pick
+# it and invoicing to bill it. The filter drops the unpaid order, the multicast sends the same
+# message to both.
+- route:
+    id: filter-and-multicast
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - log:
+            message: "Order ${body[orderId]} received, status ${body[status]}"
+        - filter:
+            expression:
+              simple:
+                expression: "${body[status]} == 'paid'"
+            steps:
+              - multicast:
+                  steps:
+                    - to:
+                        uri: direct
+                        parameters:
+                          name: warehouse
+                    - to:
+                        uri: direct
+                        parameters:
+                          name: invoicing
+- route:
+    id: warehouse
+    from:
+      uri: direct
+      parameters:
+        name: warehouse
+      steps:
+        - log:
+            message: "Warehouse: pick ${body[lines].size()} line(s) for ${body[orderId]}"
+- route:
+    id: invoicing
+    from:
+      uri: direct
+      parameters:
+        name: invoicing
+      steps:
+        - log:
+            message: "Invoicing: bill customer ${body[customer]} for ${body[orderId]}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/filter-and-multicast/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/README.md
new file mode 100644
index 000000000000..2659d8d2ebd3
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/README.md
@@ -0,0 +1,72 @@
+# Order lines
+
+An order is one message with several lines; the warehouse picks one line at a time. The splitter turns the order
+into one message per line, and the order id travels along in a header.
+
+## What you will see
+
+```text
+INFO ... order-lines.camel.yaml:20 : Order ORD-1001 with 2 line(s)
+INFO ... order-lines.camel.yaml:27 :   pick 2 x CAMEL-TSHIRT for ORD-1001
+INFO ... order-lines.camel.yaml:27 :   pick 1 x CAMEL-MUG for ORD-1001
+INFO ... order-lines.camel.yaml:29 : Order ORD-1001: all 2 line(s) sent to picking
+INFO ... order-lines.camel.yaml:20 : Order ORD-1002 with 1 line(s)
+...
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the files in place), so the run
+can be repeated.
+
+## How it works
+
+- The order is parsed with `unmarshal` and `json`, so `${body[lines]}` is a list and `${body[lines].size()}` its
+  length.
+- `setHeader` keeps the order id before the split: headers are copied to every split message, so each pick line
+  knows its order.
+- `split` with `${body[lines]}` runs its steps once per line with that line as the body; `CamelSplitIndex` and
+  `CamelSplitSize` are available inside if a count is needed.
+- After the split the route continues with the original order, which logs the confirmation.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs the number of lines.
+2. Add `split` over `${body[lines]}` and log `${body[sku]}` inside it.
+3. Keep the order id in a header before the split and use it in the pick line.
+4. Log the confirmation after the split and notice the body is the whole order again.
+
+## Try changing
+
+- Send each line to a `direct:pick` route instead of logging; the `aggregator` example collects them again.
+- Split in parallel with `parallelProcessing: true` and watch the pick lines interleave.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/order-lines.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/order-lines.citrus.it.yaml
+```
+
+The test starts the route and verifies the pick lines and the confirmation.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/order-lines.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/order-lines.camel.yaml
new file mode 100644
index 000000000000..9f8c2ad5c3d5
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/order-lines.camel.yaml
@@ -0,0 +1,30 @@
+# An order is one message with several lines; the warehouse picks one line at a time. The splitter
+# turns the order into one message per line, and the split messages keep the order id in a header.
+- route:
+    id: order-lines
+    from:
+      uri: file
+      parameters:
+        directoryName: orders
+        noop: true
+        sortBy: "file:name"
+      steps:
+        - unmarshal:
+            json:
+              library: Jackson
+        - setHeader:
+            name: orderId
+            expression:
+              simple:
+                expression: "${body[orderId]}"
+        - log:
+            message: "Order ${header.orderId} with ${body[lines].size()} line(s)"
+        - split:
+            expression:
+              simple:
+                expression: "${body[lines]}"
+            steps:
+              - log:
+                  message: "  pick ${body[qty]} x ${body[sku]} for ${header.orderId}"
+        - log:
+            message: "Order ${header.orderId}: all ${body[lines].size()} line(s) sent to picking"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1001.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1001.json
new file mode 100644
index 000000000000..3eb5f038d636
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1002.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1002.json
new file mode 100644
index 000000000000..bb7aa0e9ff1c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1003.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1003.json
new file mode 100644
index 000000000000..9edab768cbd7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/route/order-lines/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/README.md
new file mode 100644
index 000000000000..5b0266512e7e
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/README.md
@@ -0,0 +1,64 @@
+# Nightly report
+
+The shop's inventory report on a schedule. A cron expression triggers the route instead of a timer: every
+ten seconds in the demo, nightly at 02:00 with a one-line change in `application.properties`.
+
+## What you will see
+
+```text
+INFO ... nightly-report.camel.yaml:15 : Inventory report 2026-09-18 15:04:10: 120 T-shirts and 45 mugs in stock
+INFO ... nightly-report.camel.yaml:15 : Inventory report 2026-09-18 15:04:20: 120 T-shirts and 45 mugs in stock
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The `cron` component fires on the schedule `report.schedule`, a cron expression with seconds first.
+- `setBody` builds the report line with the simple language: the current time with `${date:now:...}`
+  and the stock counts from properties.
+- The Camel CLI adds the scheduler (camel-quartz) the cron component needs on its own.
+
+## Build it step by step
+
+1. Start from a timer route that logs "Inventory report" every ten seconds.
+2. Replace the timer with `cron` and the schedule `0/10 * * * * ?`; the log keeps coming every ten seconds.
+3. Add the current time to the message with `${date:now:yyyy-MM-dd HH:mm:ss}`.
+4. Move the schedule and the stock counts to `application.properties` and use them as `{{...}}`.
+5. Change the schedule to `0 0 2 * * ?` and read it back: at two in the morning, every night.
+
+## Try changing
+
+- `0 * * * * ?` runs at the top of every minute.
+- Log the report at `WARN` level when a count drops below ten: the `content-based-router` example shows
+  the `choice` you need.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/nightly-report.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/nightly-report.citrus.it.yaml
+```
+
+The test starts the route and verifies the logged line.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/application.properties
new file mode 100644
index 000000000000..b2f7fada5bd2
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/application.properties
@@ -0,0 +1,24 @@
+# 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.
+
+# When the report runs, as a cron expression (seconds minutes hours day month weekday).
+# Every ten seconds for the demo; a nightly run at 02:00 is: report.schedule=0 0 2 * * ?
+report.schedule=0/10 * * * * ?
+
+# The stock the report counts
+inventory.tshirt=120
+inventory.mug=45
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/nightly-report.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/nightly-report.camel.yaml
new file mode 100644
index 000000000000..73f0cfb27d8e
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/nightly-report/nightly-report.camel.yaml
@@ -0,0 +1,16 @@
+# The shop's inventory report on a schedule. A cron expression instead of a timer: the demo schedule
+# runs every ten seconds so there is something to see; a real nightly run is a one-line change.
+- route:
+    id: nightly-report
+    from:
+      uri: cron
+      parameters:
+        name: report
+        schedule: "{{report.schedule}}"
+      steps:
+        - setBody:
+            expression:
+              simple:
+                expression: "Inventory report ${date:now:yyyy-MM-dd HH:mm:ss}: {{inventory.tshirt}} T-shirts and {{inventory.mug}} mugs in stock"
+        - log:
+            message: "${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/OrderNumber.java b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/OrderNumber.java
new file mode 100644
index 000000000000..e1e963c051d6
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/OrderNumber.java
@@ -0,0 +1,20 @@
+package camel.example;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Hands out the shop's order numbers, ORD-1001, ORD-1002, ... A plain Java class next to the route, declared as a
+ * bean in beans.yaml and called from the route with a method expression.
+ */
+public class OrderNumber {
+
+    private final AtomicInteger counter = new AtomicInteger();
+
+    public void setStart(int start) {
+        counter.set(start - 1);
+    }
+
+    public String next() {
+        return "ORD-" + counter.incrementAndGet();
+    }
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/README.md
new file mode 100644
index 000000000000..18fc09f74ec8
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/README.md
@@ -0,0 +1,74 @@
+# Order generator
+
+The shop's order feed. A timer creates an order every five seconds, a Java bean hands out the order
+number, and the order is logged as JSON. Every later example on the ladder starts from this file and
+this order shape.
+
+## What you will see
+
+```text
+INFO ... order-generator.camel.yaml:23 : New order ORD-1001: {"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}], "status": "paid"}
+INFO ... order-generator.camel.yaml:23 : New order ORD-1002: {"orderId": "ORD-1002", "customer": "C-207", "country": "DK", "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}], "status": "paid"}
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+Stop it with `ctrl` + `c`, or from another terminal with `camel stop order-generator`.
+
+## How it works
+
+- `order-generator.camel.yaml` is the route: a `timer` fires every `order.period` milliseconds, a
+  `setHeader` asks the `orderNumber` bean for the next number with a method expression, a `setBody`
+  builds the order as JSON with the simple language, and a `log` prints it.
+- `OrderNumber.java` is a plain Java class next to the route. `beans.yaml` declares it as the bean
+  `orderNumber` and sets its first number from a property.
+- `application.properties` holds the period and the first order number; change them without touching
+  the route.
+
+## Build it step by step
+
+Ask your assistant, or type it yourself, one step at a time, and run after each:
+
+1. A timer route that logs "New order" every five seconds.
+2. Set a header `orderId` to a constant `ORD-1001` and log "New order ${header.orderId}".
+3. Add a Java class `OrderNumber` with a method `next()` that returns `ORD-` and a counter, declare it
+   in `beans.yaml`, and set the header from the bean's method instead of the constant.
+4. Set the body to a JSON order with the order id, a random customer and one line, and log the body.
+5. Move the period and the first order number to `application.properties`.
+
+## Try changing
+
+- `order.period=1000` for an order every second.
+- Add a second line to the order, or pick the sku at random from two products.
+- Log only the order id and the number of lines: `${header.orderId} has ${body.lines.size()} line(s)`
+  needs the body as an object; the `json-transform` example on the next rung shows how.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/order-generator.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/order-generator.citrus.it.yaml
+```
+
+The test starts the route and verifies the logged line.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/application.properties
new file mode 100644
index 000000000000..bf07ed7c84f1
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/application.properties
@@ -0,0 +1,21 @@
+# 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.
+
+# How often a new order is created, in milliseconds
+order.period=5000
+# The first order number
+order.first-number=1001
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/beans.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/beans.yaml
new file mode 100644
index 000000000000..444deab17be6
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/beans.yaml
@@ -0,0 +1,5 @@
+- beans:
+    - name: orderNumber
+      type: "camel.example.OrderNumber"
+      properties:
+        start: "{{order.first-number}}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/order-generator.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/order-generator.camel.yaml
new file mode 100644
index 000000000000..514f42b966b8
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/order-generator/order-generator.camel.yaml
@@ -0,0 +1,24 @@
+# The shop's order feed: a timer creates an order every few seconds. Every later example on the
+# ladder starts from this file and this order shape.
+- route:
+    id: order-generator
+    from:
+      uri: timer
+      parameters:
+        timerName: orders
+        period: "{{order.period}}"
+      steps:
+        - setHeader:
+            name: orderId
+            expression:
+              method:
+                ref: orderNumber
+                method: next
+        - setBody:
+            expression:
+              simple:
+                expression: |-
+                  {"orderId": "${header.orderId}", "customer": "C-${random(100,999)}", "country": "DK",
+                   "lines": [{"sku": "CAMEL-TSHIRT", "qty": ${random(1,3)}, "price": 19.95}], "status": "paid"}
+        - log:
+            message: "New order ${header.orderId}: ${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/README.md
new file mode 100644
index 000000000000..a5461677e08d
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/README.md
@@ -0,0 +1,74 @@
+# Properties and profiles
+
+One route, two configurations. `application.properties` is what `camel run` uses; `application-prod.properties`
+holds the values that differ in production and is chosen with `--profile=prod`.
+
+## What you will see
+
+```text
+camel run *
+INFO ... properties-and-profiles.camel.yaml:15 : Welcome to Camel Shop (development), prices in EUR
+
+camel run * --profile=prod
+INFO ... properties-and-profiles.camel.yaml:15 : Welcome to Camel Shop, prices in USD
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+and then the production profile:
+
+```shell
+camel run * --profile=prod
+```
+
+## How it works
+
+- `{{shop.name}}` and `{{shop.currency}}` in the route are property placeholders; Camel resolves them
+  from `application.properties` at startup.
+- With `--profile=prod` Camel also reads `application-prod.properties`, and a value there wins over the
+  same key in `application.properties`. Only the differing values need to be in the profile file.
+- `welcome.period` is only in `application.properties`, so both profiles share it.
+
+## Build it step by step
+
+1. A timer route that logs "Welcome to Camel Shop".
+2. Move the shop name to `application.properties` as `shop.name` and use `{{shop.name}}` in the message.
+3. Add `shop.currency` the same way and mention it in the message.
+4. Create `application-prod.properties` with a different name and currency, run with `--profile=prod`,
+   and see the message change.
+5. Move the timer period to a property that only `application.properties` has.
+
+## Try changing
+
+- Override a single value from the command line: `camel run * --prop=shop.currency=DKK`.
+- Add an `application-test.properties` and run `--profile=test`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/properties-and-profiles.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/properties-and-profiles.citrus.it.yaml
+```
+
+The test starts the route and verifies the logged line.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application-prod.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application-prod.properties
new file mode 100644
index 000000000000..33d3d1cdeb86
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application-prod.properties
@@ -0,0 +1,21 @@
+# 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.
+
+# The production configuration, used with camel run --profile=prod.
+# Only the values that differ are needed; the rest come from application.properties.
+shop.name=Camel Shop
+shop.currency=USD
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application.properties
new file mode 100644
index 000000000000..050a9e5f3e88
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/application.properties
@@ -0,0 +1,21 @@
+# 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.
+
+# The default configuration, used with plain camel run
+shop.name=Camel Shop (development)
+shop.currency=EUR
+welcome.period=3000
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/properties-and-profiles.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/properties-and-profiles.camel.yaml
new file mode 100644
index 000000000000..6882e660a65d
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/run/properties-and-profiles/properties-and-profiles.camel.yaml
@@ -0,0 +1,16 @@
+# The same route with two configurations: application.properties for development and
+# application-prod.properties for production, chosen with --profile=prod.
+- route:
+    id: welcome
+    from:
+      uri: timer
+      parameters:
+        timerName: welcome
+        period: "{{welcome.period}}"
+      steps:
+        - setBody:
+            expression:
+              simple:
+                expression: "Welcome to {{shop.name}}, prices in {{shop.currency}}"
+        - log:
+            message: "${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/README.md
new file mode 100644
index 000000000000..8ed95b6f7301
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/README.md
@@ -0,0 +1,69 @@
+# CSV to JSON
+
+The accountant drops a CSV of invoices in the inbox. Each line becomes one JSON invoice, logged and written to
+the outbox as its own file.
+
+## What you will see
+
+```text
+INFO ... csv-to-json.camel.yaml:29 : Invoice INV-2001: {"invoiceId":"INV-2001","orderId":"ORD-1001","customer":"C-482","amount":"49.40","currency":"EUR","dueDate":"2026-10-01"}
+INFO ... csv-to-json.camel.yaml:29 : Invoice INV-2002: {"invoiceId":"INV-2002","orderId":"ORD-1002",...}
+INFO ... csv-to-json.camel.yaml:29 : Invoice INV-2003: {"invoiceId":"INV-2003","orderId":"ORD-1003",...}
+
+$ ls outbox
+INV-2001.json INV-2002.json INV-2003.json
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- `unmarshal` with the `csv` data format reads `inbox/invoices.csv`; `captureHeaderRecord` takes the first line
+  as the field names and `useMaps` makes each following line a map.
+- `split` turns the list of maps into one message per invoice.
+- Inside the split, the invoice id is kept in a header, `marshal` with `json` writes the map as JSON, and the
+  `file` producer names the output file after the invoice.
+- Values are strings, as in the CSV; the `data-mapping` example shows how to compute and type fields.
+
+## Build it step by step
+
+1. A `file` route on `inbox` that logs the CSV as text.
+2. Add `unmarshal` with `csv` and log the body: a list of maps.
+3. Add `split` over `${body}` and log each invoice.
+4. Add `marshal` with `json` inside the split.
+5. Write each invoice to `outbox`, named after its id.
+
+## Try changing
+
+- Aggregate the amounts per customer before writing: the `aggregator` example shows the EIP.
+- Delete or move the CSV after reading by dropping `noop: true` and adding `move: done`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/csv-to-json.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/csv-to-json.citrus.it.yaml
+```
+
+The test starts the route and verifies that the three invoices are logged as JSON.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/csv-to-json.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/csv-to-json.camel.yaml
new file mode 100644
index 000000000000..4fdf03dba037
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/csv-to-json.camel.yaml
@@ -0,0 +1,35 @@
+# The accountant drops a CSV of invoices in the inbox; each line becomes one JSON invoice, logged and
+# written to the outbox as its own file.
+- route:
+    id: csv-to-json
+    from:
+      uri: file
+      parameters:
+        directoryName: inbox
+        noop: true
+        include: ".*\\.csv"
+      steps:
+        - unmarshal:
+            csv:
+              useMaps: true
+              captureHeaderRecord: true
+        - split:
+            expression:
+              simple:
+                expression: "${body}"
+            steps:
+              - setHeader:
+                  name: invoiceId
+                  expression:
+                    simple:
+                      expression: "${body[invoiceId]}"
+              - marshal:
+                  json:
+                    library: Jackson
+              - log:
+                  message: "Invoice ${header.invoiceId}: ${body}"
+              - to:
+                  uri: file
+                  parameters:
+                    directoryName: outbox
+                    fileName: "${header.invoiceId}.json"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/inbox/invoices.csv b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/inbox/invoices.csv
new file mode 100644
index 000000000000..8a2891332396
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/csv-to-json/inbox/invoices.csv
@@ -0,0 +1,4 @@
+invoiceId,orderId,customer,amount,currency,dueDate
+INV-2001,ORD-1001,C-482,49.40,EUR,2026-10-01
+INV-2002,ORD-1002,C-207,19.95,EUR,2026-10-01
+INV-2003,ORD-1003,C-134,59.85,EUR,2026-10-02
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/README.md
new file mode 100644
index 000000000000..7ed0376e65b9
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/README.md
@@ -0,0 +1,65 @@
+# Data mapping
+
+The case every integration has: the shop's order mapped field by field to the courier's shipment format, which has
+different names, a different structure, and values the order does not carry. The mapping is a Groovy script.
+
+## What you will see
+
+```text
+INFO ... data-mapping.camel.yaml:27 : Shipment for the courier: {"shipmentRef":"SHIP-1001","recipient":{"customerNo":"C-482","countryCode":"DK"},"parcels":[{"article":"CAMEL-TSHIRT","pieces":2},{"article":"CAMEL-MUG","pieces":1}],"totalPieces":3,"service":"domestic","createdAt":"2026-09-18"}
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The order in `order.json` is parsed with `unmarshal` and the `json` data format, so the script works on a map,
+  not on text.
+- `setBody` with a `groovy` expression runs `shipment-mapping.groovy`: `resource:file:` loads the script from the
+  file next to the route. The script's last expression, a map with the courier's field names, becomes the body.
+- `marshal` with `json` writes the shipment out. Renamed fields, a nested `recipient`, one `parcels` entry per
+  line, a computed `totalPieces`, a `service` chosen from the country, and a `createdAt` the order never had.
+
+## Build it step by step
+
+1. A one-shot timer route that sets the body from `order.json`, unmarshals it with `json`, and logs
+   `${body[orderId]}`.
+2. Add a `setBody` with an inline `groovy` expression returning `[shipmentRef: body.orderId]` and log the body.
+3. Move the expression into `shipment-mapping.groovy` and load it with `resource:file:`.
+4. Grow the map: the recipient, the parcels with `collect`, the total with `sum`.
+5. Add `marshal` with `json` and log the shipment.
+
+## Try changing
+
+- Map the country to the courier's service codes with a Groovy map: `[DK: 'DOM', SE: 'NORDIC'][order.country]`.
+- Do the same mapping with a Java bean instead of Groovy; the `routes` quick-start shows a bean.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/data-mapping.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/data-mapping.citrus.it.yaml
+```
+
+The test starts the route and verifies that the shipment is logged with the courier's fields.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/data-mapping.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/data-mapping.camel.yaml
new file mode 100644
index 000000000000..57deb54c5dab
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/data-mapping.camel.yaml
@@ -0,0 +1,28 @@
+# The case every integration has: the shop's order mapped field by field to the courier's shipment
+# format, which has different names, a different structure, and values the order does not carry.
+# The order is parsed to a map, the Groovy script shipment-mapping.groovy builds the shipment map,
+# and it is written out as JSON.
+- route:
+    id: data-mapping
+    from:
+      uri: timer
+      parameters:
+        timerName: order
+        repeatCount: 1
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: "resource:file:order.json"
+        - unmarshal:
+            json:
+              library: Jackson
+        - setBody:
+            expression:
+              groovy:
+                expression: "resource:file:shipment-mapping.groovy"
+        - marshal:
+            json:
+              library: Jackson
+        - log:
+            message: "Shipment for the courier: ${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/order.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/order.json
new file mode 100644
index 000000000000..2327db569ca5
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/order.json
@@ -0,0 +1,3 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}],
+ "status": "paid"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/shipment-mapping.groovy b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/shipment-mapping.groovy
new file mode 100644
index 000000000000..679609aebd42
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/data-mapping/shipment-mapping.groovy
@@ -0,0 +1,12 @@
+// Maps the shop's order (the message body, parsed from JSON into a map) to the courier's shipment
+// format. Runs as a Groovy script from the route: the last expression is the new message body.
+def order = body
+
+[
+    shipmentRef : "SHIP-" + order.orderId.replace("ORD-", ""),
+    recipient   : [customerNo: order.customer, countryCode: order.country],
+    parcels     : order.lines.collect { line -> [article: line.sku, pieces: line.qty] },
+    totalPieces : order.lines.sum { line -> line.qty },
+    service     : order.country == "DK" ? "domestic" : "international",
+    createdAt   : java.time.LocalDate.now().toString()
+]
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/README.md
new file mode 100644
index 000000000000..5a4909701348
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/README.md
@@ -0,0 +1,67 @@
+# Groovy
+
+Two orders come in, one with a valid customer email and one with a bad one. A Groovy expression checks the address
+with Apache Commons Validator, a third-party library the Camel CLI downloads because `application.properties`
+declares it.
+
+## What you will see
+
+```text
+INFO ... groovy.camel.yaml:28 : Order ORD-1001 accepted: anna@example.com is a valid address
+INFO ... groovy.camel.yaml:32 : Order ORD-1002 rejected: not-an-address is not an email address
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The timer fires twice with `includeMetadata: true`, so `CamelTimerCounter` tells the first order from the
+  second; a simple expression picks `order.json` or `order-bad-email.json` from it.
+- `unmarshal` with `json` parses the order, so the Groovy expression reads `body.email` on a map.
+- `choice` with a `groovy` expression: `EmailValidator.getInstance().isValid(body.email)` from Commons Validator.
+- `camel.jbang.dependencies=commons-validator:commons-validator:1.10.1` in `application.properties` is how a
+  route declares a library that is not a Camel component; the Camel CLI downloads it.
+
+## Build it step by step
+
+1. A one-shot timer route that sets the body from `order.json`, unmarshals it, and logs `${body[email]}`.
+2. Add a `choice` with a `groovy` expression `body.email.contains('@')` and log accepted or rejected.
+3. Replace the check with Commons Validator's `EmailValidator` and declare the dependency in
+   `application.properties`.
+4. Let the timer fire twice with `includeMetadata: true` and pick the second file for the second order.
+
+## Try changing
+
+- Validate the country code too: `body.country in ['DK', 'SE', 'NO']`.
+- Put the check in a script file, `validate-order.groovy`, and load it with `resource:file:`, as the
+  `data-mapping` example does.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/groovy.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/groovy.citrus.it.yaml
+```
+
+The test starts the route and verifies that one order is accepted and one rejected.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/application.properties
new file mode 100644
index 000000000000..6fda14e7eb16
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/application.properties
@@ -0,0 +1,19 @@
+# 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.
+
+# A third-party library the Groovy expression uses; the Camel CLI downloads it
+camel.jbang.dependencies=commons-validator:commons-validator:1.10.1
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/groovy.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/groovy.camel.yaml
new file mode 100644
index 000000000000..097bffc71d4b
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/groovy.camel.yaml
@@ -0,0 +1,33 @@
+# Two orders, one with a valid customer email and one without. A Groovy expression checks the
+# address with Apache Commons Validator, a third-party library the Camel CLI downloads because it
+# is declared in application.properties.
+- route:
+    id: groovy
+    from:
+      uri: timer
+      parameters:
+        timerName: orders
+        repeatCount: 2
+        includeMetadata: true
+      steps:
+        - setBody:
+            expression:
+              simple:
+                expression: "resource:file:${exchangeProperty.CamelTimerCounter == 1 ? 'order.json' : 'order-bad-email.json'}"
+        - unmarshal:
+            json:
+              library: Jackson
+        - choice:
+            when:
+              - expression:
+                  groovy:
+                    expression: |-
+                      import org.apache.commons.validator.routines.EmailValidator
+                      EmailValidator.getInstance().isValid(body.email)
+                steps:
+                  - log:
+                      message: "Order ${body[orderId]} accepted: ${body[email]} is a valid address"
+            otherwise:
+              steps:
+                - log:
+                    message: "Order ${body[orderId]} rejected: ${body[email]} is not an email address"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order-bad-email.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order-bad-email.json
new file mode 100644
index 000000000000..687988af1d62
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order-bad-email.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "email": "not-an-address", "country": "DK",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}], "status": "paid"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order.json
new file mode 100644
index 000000000000..1125f80eb919
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/groovy/order.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "email": "anna@example.com", "country": "DK",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}], "status": "paid"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/README.md
new file mode 100644
index 000000000000..f7e3d2cc2546
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/README.md
@@ -0,0 +1,68 @@
+# JSON transform
+
+The shop's order reshaped for the warehouse. jsonpath reads single values out of the order, jq builds the pick
+list the warehouse wants: only the sku and the quantity of each line.
+
+## What you will see
+
+```text
+INFO ... json-transform.camel.yaml:25 : Order ORD-1001 with 2 lines: {"orderId": "ORD-1001", "customer": "C-482", ...}
+INFO ... json-transform.camel.yaml:32 : Pick list for the warehouse: {
+  "order" : "ORD-1001",
+  "country" : "DK",
+  "pick" : [ { "sku" : "CAMEL-TSHIRT", "qty" : 2 }, { "sku" : "CAMEL-MUG", "qty" : 1 } ]
+}
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The order comes from `order.json`; `resource:file:` in a constant expression loads a file as the body.
+- `jsonpath` expressions pick the order id and the number of lines into headers.
+- `transform` with a `jq` expression builds a new document from the old one: `.orderId` becomes `order`, and
+  `[.lines[] | {sku, qty}]` keeps two fields of every line.
+- The Camel CLI adds the jq and jsonpath languages on its own.
+
+## Build it step by step
+
+1. A one-shot timer route that sets the body from `order.json` and logs it.
+2. Read the order id into a header with `jsonpath: $.orderId` and log it.
+3. Add the number of lines with `jsonpath: $.lines.length()`.
+4. Add a `transform` step with a jq expression that keeps only the order id, and log the result.
+5. Extend the jq expression with the country and the pick list of sku and qty per line.
+
+## Try changing
+
+- Add the total quantity: `total: ([.lines[].qty] | add)` in the jq expression.
+- Filter lines with more than one piece: `[.lines[] | select(.qty > 1)]`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/json-transform.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/json-transform.citrus.it.yaml
+```
+
+The test starts the route and verifies that the pick list is logged.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/json-transform.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/json-transform.camel.yaml
new file mode 100644
index 000000000000..933bb41d7f35
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/json-transform.camel.yaml
@@ -0,0 +1,33 @@
+# Reshape the shop's order for the warehouse: jq builds the pick list the warehouse wants, jsonpath
+# picks single values out of the order.
+- route:
+    id: json-transform
+    from:
+      uri: timer
+      parameters:
+        timerName: order
+        repeatCount: 1
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: "resource:file:order.json"
+        - setHeader:
+            name: orderId
+            expression:
+              jsonpath:
+                expression: "$.orderId"
+        - setHeader:
+            name: itemCount
+            expression:
+              jsonpath:
+                expression: "$.lines.length()"
+        - log:
+            message: "Order ${header.orderId} with ${header.itemCount} lines: ${body}"
+        - transform:
+            expression:
+              jq:
+                expression: "{order: .orderId, country: .country, pick: [.lines[] | {sku: .sku, qty: .qty}]}"
+                resultType: java.lang.String
+        - log:
+            message: "Pick list for the warehouse: ${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/order.json b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/order.json
new file mode 100644
index 000000000000..2327db569ca5
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/json-transform/order.json
@@ -0,0 +1,3 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}],
+ "status": "paid"}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/README.md
new file mode 100644
index 000000000000..b7e7b725309c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/README.md
@@ -0,0 +1,67 @@
+# XML to JSON
+
+The supplier sends orders as XML, the shop works in JSON. The Jackson XML data format reads the XML into a map
+and the Jackson JSON data format writes the map out: no mapping code, elements and attributes become fields.
+
+## What you will see
+
+```text
+INFO ... xml-to-json.camel.yaml:13 : Supplier order as XML: <?xml version="1.0" encoding="UTF-8"?><order id="ORD-1001" country="DK">...
+INFO ... xml-to-json.camel.yaml:20 : The same order as JSON: {"id":"ORD-1001","country":"DK","customer":"C-482","line":[{"sku":"CAMEL-TSHIRT","qty":"2","price":"19.95"},{"sku":"CAMEL-MUG","qty":"1","price":"9.50"}],"status":"paid"}
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The `file` consumer reads `inbox/supplier-order.xml`; `noop: true` leaves the file where it is so the example
+  can run again.
+- `unmarshal` with `jacksonXml` turns the XML into a map: attributes and child elements become keys, the two
+  `line` elements become a list.
+- `marshal` with `json` writes that map as JSON. Values stay strings, because XML has no numbers; the
+  `data-mapping` example shows how to shape and type the result.
+- The way back, JSON to XML, needs a name for the root element, which the Jackson XML data format takes from a
+  class; that comes with the bean examples later on the ladder.
+
+## Build it step by step
+
+1. A `file` route on `inbox` that logs the XML it reads.
+2. Add `unmarshal` with `jacksonXml` and log the body: a map now.
+3. Add `marshal` with `json` and log again: the same order as JSON.
+4. Drop a second XML file into `inbox` while it runs and watch it get converted too.
+
+## Try changing
+
+- Add `prettyPrint: true` to the `json` data format for indented output.
+- Replace `jacksonXml` by `xslt` when the JSON should have a different shape than the XML: the `xslt` example
+  next door does that for the packing slip.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/xml-to-json.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/xml-to-json.citrus.it.yaml
+```
+
+The test starts the route and verifies that the order is logged as JSON.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/inbox/supplier-order.xml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/inbox/supplier-order.xml
new file mode 100644
index 000000000000..67fc5e6f631c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/inbox/supplier-order.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<order id="ORD-1001" country="DK">
+  <customer>C-482</customer>
+  <line sku="CAMEL-TSHIRT" qty="2" price="19.95"/>
+  <line sku="CAMEL-MUG" qty="1" price="9.50"/>
+  <status>paid</status>
+</order>
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/xml-to-json.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/xml-to-json.camel.yaml
new file mode 100644
index 000000000000..a4c7225f7cdd
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xml-to-json/xml-to-json.camel.yaml
@@ -0,0 +1,21 @@
+# The supplier sends orders as XML, the shop works in JSON. The Jackson XML data format reads the
+# XML into a map and the Jackson JSON data format writes the map out: no mapping code, the XML
+# elements and attributes become JSON fields.
+- route:
+    id: xml-to-json
+    from:
+      uri: file
+      parameters:
+        directoryName: inbox
+        noop: true
+        include: ".*\\.xml"
+      steps:
+        - log:
+            message: "Supplier order as XML: ${body}"
+        - unmarshal:
+            jacksonXml: {}
+        - marshal:
+            json:
+              library: Jackson
+        - log:
+            message: "The same order as JSON: ${body}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/README.md b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/README.md
new file mode 100644
index 000000000000..4d799391f234
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/README.md
@@ -0,0 +1,66 @@
+# XSLT
+
+The supplier's XML order becomes the packing slip the warehouse prints, transformed by a stylesheet: one item per
+line and the total pieces to pick.
+
+## What you will see
+
+```text
+INFO ... xslt.camel.yaml:16 : Packing slip:
+<?xml version="1.0" encoding="UTF-8"?><packingSlip order="ORD-1001" customer="C-482" country="DK">
+    <item sku="CAMEL-TSHIRT" pieces="2"/>
+    <item sku="CAMEL-MUG" pieces="1"/>
+    <pieces>3</pieces>
+</packingSlip>
+```
+
+## Install Camel CLI
+
+Install [JBang](https://www.jbang.dev/download/) and the Camel CLI as described in the
+[root README](../../README.md#install-the-camel-cli); `camel --version` confirms the install.
+
+## Run it
+
+```shell
+camel run *
+```
+
+## How it works
+
+- The `file` consumer reads `inbox/supplier-order.xml` and leaves it there with `noop: true`.
+- `to: xslt` applies `packing-slip.xsl`: the template matches `/order`, writes one `item` per `line` with the
+  attributes renamed, and sums the quantities with `sum(line/@qty)`.
+- `${prettyBody}` in the log indents the XML.
+
+## Build it step by step
+
+1. A `file` route on `inbox` that logs the XML.
+2. Add `to: xslt` with a stylesheet that copies the order id into a `packingSlip` root element.
+3. Add a `for-each` over the lines writing one `item` each.
+4. Add the `pieces` total with `sum()`.
+
+## Try changing
+
+- Produce HTML instead: change `xsl:output` to `html` and write a table.
+- Use XSLT 2.0 or 3.0 functions such as `current-dateTime()`: switch to the `xslt-saxon` component.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/) YAML DSL,
+`test/xslt.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/xslt.citrus.it.yaml
+```
+
+The test starts the route and verifies that the packing slip is logged.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/application.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/application.properties
new file mode 100644
index 000000000000..13a83393a912
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/inbox/supplier-order.xml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/inbox/supplier-order.xml
new file mode 100644
index 000000000000..67fc5e6f631c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/inbox/supplier-order.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<order id="ORD-1001" country="DK">
+  <customer>C-482</customer>
+  <line sku="CAMEL-TSHIRT" qty="2" price="19.95"/>
+  <line sku="CAMEL-MUG" qty="1" price="9.50"/>
+  <status>paid</status>
+</order>
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/packing-slip.xsl b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/packing-slip.xsl
new file mode 100644
index 000000000000..22085915d74a
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/packing-slip.xsl
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output method="xml" indent="yes"/>
+
+  <!-- The supplier's order becomes the packing slip the warehouse prints: one item per line, and
+       the number of pieces to pick in total. -->
+  <xsl:template match="/order">
+    <packingSlip order="{@id}" customer="{customer}" country="{@country}">
+      <xsl:for-each select="line">
+        <item sku="{@sku}" pieces="{@qty}"/>
+      </xsl:for-each>
+      <pieces><xsl:value-of select="sum(line/@qty)"/></pieces>
+    </packingSlip>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/xslt.camel.yaml b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/xslt.camel.yaml
new file mode 100644
index 000000000000..9063f8d37e51
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/transform/xslt/xslt.camel.yaml
@@ -0,0 +1,17 @@
+# The supplier's XML order dropped in the inbox becomes the packing slip the warehouse prints,
+# transformed by the stylesheet packing-slip.xsl.
+- route:
+    id: xslt
+    from:
+      uri: file
+      parameters:
+        directoryName: inbox
+        noop: true
+        include: ".*\\.xml"
+      steps:
+        - to:
+            uri: xslt
+            parameters:
+              resourceUri: packing-slip.xsl
+        - log:
+            message: "Packing slip:\n${prettyBody}"
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/Greeter.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/Greeter.java
index ae48efcb5fd7..264b731b4e3b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/Greeter.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/Greeter.java
@@ -16,30 +16,25 @@
  */
 package camel.example;
 
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-
 /**
- * Test fixture mirroring {@code src/main/resources/examples/routes/Greeter.java}, which the CLI compiles at runtime. A
- * compiled copy is needed on the test classpath so that {@code examples/routes/beans.yaml} can instantiate its
- * {@code greeter} bean while {@link org.apache.camel.dsl.jbang.core.common.ExampleRoutesLoadTest} pre-parses it.
+ * Test fixture mirroring {@code src/main/resources/examples/quick-start/routes/Greeter.java}, which the CLI compiles at
+ * runtime. A compiled copy is needed on the test classpath so that {@code examples/quick-start/routes/beans.yaml} can
+ * instantiate its {@code greeter} bean while {@link org.apache.camel.dsl.jbang.core.common.ExampleRoutesLoadTest}
+ * pre-parses it.
  *
- * Keep this in sync with the example source. Only the type and its {@code message} property are load-bearing for the
- * test: a missing property fails bean binding loudly, whereas the {@link #process} behavior is never exercised (the
- * test does not start the context), so behavioral drift would go unnoticed.
+ * Keep this in sync with the example source (synced from camel-jbang-examples). Only the type and its {@code greeting}
+ * property are load-bearing for the test: a missing property fails bean binding loudly, whereas {@link #greet} is never
+ * called (the test does not start the context), so behavioral drift would go unnoticed.
  */
-public class Greeter implements Processor {
+public class Greeter {
 
-    private String message;
+    private String greeting;
 
-    public void setMessage(String message) {
-        this.message = message;
+    public void setGreeting(String greeting) {
+        this.greeting = greeting;
     }
 
-    @Override
-    public void process(Exchange exchange) throws Exception {
-        String body = exchange.getIn().getBody(String.class);
-        exchange.getIn().setBody(message + " " + body);
+    public String greet(String name) {
+        return greeting + ", " + name + "!";
     }
-
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/OrderNumber.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/OrderNumber.java
new file mode 100644
index 000000000000..7f5dad0be5d7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/camel/example/OrderNumber.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package camel.example;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Test fixture mirroring {@code src/main/resources/examples/run/order-generator/OrderNumber.java}, which the CLI
+ * compiles at runtime, so that {@code examples/run/order-generator/beans.yaml} can instantiate its {@code orderNumber}
+ * bean while {@link org.apache.camel.dsl.jbang.core.common.ExampleRoutesLoadTest} pre-parses it.
+ *
+ * Keep this in sync with the example source (synced from camel-jbang-examples). Only the type and its {@code start}
+ * property are load-bearing for the test.
+ */
+public class OrderNumber {
+
+    private final AtomicInteger counter = new AtomicInteger();
+
+    public void setStart(int start) {
+        counter.set(start - 1);
+    }
+
+    public String next() {
+        return "ORD-" + counter.incrementAndGet();
+    }
+}