diff --git a/CHANGELOG.md b/CHANGELOG.md
index f334284..4338492 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,14 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
## [Unreleased]
+### Changed
+
+- A blank driver (`driver.add --shim-class`) now starts with the documents the engine and
+ Designer expect, as templates: a filter with User and Group and the usual attributes
+ synchronised both ways, shim settings with one example parameter per section (driver,
+ Subscriber, Publisher heartbeat), and an empty configuration-values document — instead of an
+ empty `` and bare option groups.
+
## [0.14.0] - 2026-10-07
### Added
diff --git a/src/main/java/com/pointblue/dirxml/dev/edit/DriverOps.java b/src/main/java/com/pointblue/dirxml/dev/edit/DriverOps.java
index da84ebe..904b113 100644
--- a/src/main/java/com/pointblue/dirxml/dev/edit/DriverOps.java
+++ b/src/main/java/com/pointblue/dirxml/dev/edit/DriverOps.java
@@ -27,7 +27,10 @@
* artifacts the export carries are added to the tree's Library when absent
* (matched by name; an existing one is kept as is);
*
{@code --copy-of D}: a clone of an existing driver, links re-pointed;
- * {@code --shim-class C}: a blank driver with an empty filter.
+ * {@code --shim-class C}: a blank driver with a starting filter (User and Group, the
+ * usual attributes synchronised both ways), shim settings with one example parameter per
+ * section, and an empty configuration-values document — every document the engine and
+ * Designer expect, as templates to edit rather than blanks to invent.
*
* Package meta travels with the copied artifacts, so the deployer treats them as
* packaged and the project writer will refuse a packaged driver.
@@ -37,6 +40,41 @@ public final class DriverOps {
private DriverOps() {
}
+ /** A starting filter for a blank driver: User and Group, the usual attributes, synchronised both ways. */
+ static final String BLANK_FILTER = ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + "";
+
+ /** Shim settings for a blank driver: the three sections, each with one example parameter in the engine's definition form. */
+ static final String BLANK_SHIM_CONFIG = ""
+ + ""
+ + ""
+ + "A driver parameter the shim reads from its init document (replace or remove)."
+ + ""
+ + ""
+ + ""
+ + "A Subscriber channel parameter (replace or remove)."
+ + ""
+ + ""
+ + ""
+ + "Minutes of Publisher silence after which the shim sends a status document; 0 disables it.1"
+ + ""
+ + "";
+
public static final class Add implements Operation {
private final String name;
private final Path export;
@@ -113,10 +151,10 @@ public void apply(DriverSet ds, Transaction tx) throws Refusal, IOException {
d.shimClass = shim;
d.shimAuthServer = authServer;
d.shimAuthId = authId;
- d.config.put(Driver.DRIVER_FILTER, CanonicalXml.parse("").getDocumentElement());
+ d.config.put(Driver.DRIVER_FILTER, CanonicalXml.parse(BLANK_FILTER).getDocumentElement());
d.config.put(Driver.SHIM_CONFIG_INFO, CanonicalXml.parse(
- "")
- .getDocumentElement());
+ BLANK_SHIM_CONFIG.replace("%NAME%", name.replace("&", "&").replace("\"", """))).getDocumentElement());
+ d.config.put(Driver.CONFIG_VALUES, CanonicalXml.parse("").getDocumentElement());
}
if (ds.dn != null && !ds.dn.isBlank()) {
d.dn = "cn=" + name + "," + ds.dn;
diff --git a/src/test/java/com/pointblue/dirxml/dev/edit/DriverOpsTest.java b/src/test/java/com/pointblue/dirxml/dev/edit/DriverOpsTest.java
index e17ccf3..9ddacf6 100644
--- a/src/test/java/com/pointblue/dirxml/dev/edit/DriverOpsTest.java
+++ b/src/test/java/com/pointblue/dirxml/dev/edit/DriverOpsTest.java
@@ -62,9 +62,20 @@ public void blankDriver() throws IOException {
Driver d = AsCodeReader.read(tree).driver("Loop");
assertEquals("com.example.Loop", d.shimClass);
assertEquals("svc", d.shimAuthId);
- assertNotNull(d.config.get(Driver.DRIVER_FILTER));
- assertNotNull(d.config.get(Driver.SHIM_CONFIG_INFO));
- assertTrue(r.report.ok());
+ // the templates: a starting filter, shim settings with an example per section, an empty configuration-values
+ org.w3c.dom.Element filter = d.config.get(Driver.DRIVER_FILTER);
+ assertNotNull(filter);
+ assertEquals(2, filter.getElementsByTagName("filter-class").getLength());
+ assertEquals("User", ((org.w3c.dom.Element) filter.getElementsByTagName("filter-class").item(0)).getAttribute("class-name"));
+ assertTrue(filter.getElementsByTagName("filter-attr").getLength() >= 8);
+ org.w3c.dom.Element shim = d.config.get(Driver.SHIM_CONFIG_INFO);
+ assertNotNull(shim);
+ assertEquals("Loop", shim.getAttribute("name"));
+ assertEquals(3, shim.getElementsByTagName("definition").getLength());
+ assertEquals(1, shim.getElementsByTagName("publisher-options").getLength());
+ assertNotNull(d.config.get(Driver.CONFIG_VALUES));
+ assertEquals("definitions", d.config.get(Driver.CONFIG_VALUES).getElementsByTagName("definitions").item(0).getNodeName());
+ assertTrue(r.report.text(), r.report.ok());
assertTrue(run(new DriverOps.Add("Blank2", null, null, false, null, null, null)).refusal.contains("--shim-class"));
}