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

janhoy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new ef23d0f8ad2 SOLR-18518: Port the snapshot commands to picocli (#5044)
ef23d0f8ad2 is described below

commit ef23d0f8ad23168a46da5b257498a76d07a8868c
Author: Serhiy Bzhezytskyy <[email protected]>
AuthorDate: Thu Oct 8 19:21:36 2026 +0300

    SOLR-18518: Port the snapshot commands to picocli (#5044)
    
    Co-authored-by: Jan Høydahl <[email protected]>
---
 .../SOLR-17697-picocli-experimental-cli.yml        |   2 +
 .../src/java/org/apache/solr/cli/CLIUtils.java     |  42 ++++++
 .../org/apache/solr/cli/CollectionNameOptions.java |  32 +++++
 .../org/apache/solr/cli/SnapshotCreateShim.java    |  42 ++++++
 .../org/apache/solr/cli/SnapshotCreateTool.java    |  43 +++++-
 .../org/apache/solr/cli/SnapshotDeleteShim.java    |  42 ++++++
 .../org/apache/solr/cli/SnapshotDeleteTool.java    |  43 +++++-
 .../org/apache/solr/cli/SnapshotDescribeShim.java  |  42 ++++++
 .../org/apache/solr/cli/SnapshotDescribeTool.java  |  43 +++++-
 .../org/apache/solr/cli/SnapshotExportShim.java    |  42 ++++++
 .../org/apache/solr/cli/SnapshotExportTool.java    |  93 ++++++++++++-
 .../java/org/apache/solr/cli/SnapshotListShim.java |  42 ++++++
 .../java/org/apache/solr/cli/SnapshotListTool.java |  32 ++++-
 .../org/apache/solr/cli/SnapshotNameOptions.java   |  30 +++++
 .../src/java/org/apache/solr/cli/SnapshotTool.java |  46 +++++++
 .../core/src/java/org/apache/solr/cli/SolrCLI.java |   8 +-
 .../solr/cli/SnapshotExportToolPicocliTest.java    |  32 +++++
 .../apache/solr/cli/SnapshotExportToolTest.java    |  32 ++++-
 .../apache/solr/cli/SnapshotToolsPicocliTest.java  | 147 +++++++++++++++++++++
 .../org/apache/solr/cli/SnapshotToolsTest.java     |  91 +++++++++++++
 .../modules/deployment-guide/deployment-nav.adoc   |   6 +
 .../modules/deployment-guide/pages/cli/index.adoc  |   6 +
 .../pages/cli/solr-snapshot-create.adoc            |  84 ++++++++++++
 .../pages/cli/solr-snapshot-delete.adoc            |  84 ++++++++++++
 .../pages/cli/solr-snapshot-describe.adoc          |  85 ++++++++++++
 .../pages/cli/solr-snapshot-export.adoc            |  94 +++++++++++++
 .../pages/cli/solr-snapshot-list.adoc              |  81 ++++++++++++
 .../deployment-guide/pages/cli/solr-snapshot.adoc  |  74 +++++++++++
 .../pages/major-changes-in-solr-10.adoc            |  16 +++
 29 files changed, 1449 insertions(+), 7 deletions(-)

diff --git a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml 
b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
index 58cd2b4142a..5037bd6b2df 100644
--- a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
+++ b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
@@ -27,3 +27,5 @@ links:
     url: https://issues.apache.org/jira/browse/SOLR-18516
   - name: SOLR-18519
     url: https://issues.apache.org/jira/browse/SOLR-18519
+  - name: SOLR-18518
+    url: https://issues.apache.org/jira/browse/SOLR-18518
diff --git a/solr/core/src/java/org/apache/solr/cli/CLIUtils.java 
b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
index f60d03c3574..3c5d2a98ad6 100644
--- a/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
+++ b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
@@ -247,6 +247,48 @@ public final class CLIUtils {
     return solrUrl;
   }
 
+  /**
+   * The picocli counterpart of {@link #normalizeSolrUrl(CommandLine)}: {@code 
--solr-url}, else the
+   * connection named by {@code --solr-connection} or {@code --zk-host} (or 
the matching property
+   * when the option is absent), else the default URL with the same warning.
+   *
+   * @param connectionOptions the parsed connection group, or null if none of 
its options was given
+   */
+  static String resolveSolrUrl(ConnectionOptions connectionOptions, String 
credentials)
+      throws Exception {
+    String solrUrl = connectionOptions != null ? connectionOptions.solrUrl : 
null;
+    if (solrUrl == null) {
+      String solrConnection =
+          (connectionOptions != null && connectionOptions.solrConnection != 
null)
+              ? connectionOptions.solrConnection
+              : EnvUtils.getProperty("solr.connection");
+      String zkHost =
+          (connectionOptions != null && connectionOptions.zkHost != null)
+              ? connectionOptions.zkHost
+              : EnvUtils.getProperty("zkHost");
+      if (solrConnection != null && !solrConnection.isBlank()) {
+        solrUrl =
+            solrUrlFromConnection(
+                
CloudSolrClient.CloudSolrClientConnection.parse(solrConnection), credentials);
+      } else if (zkHost != null && !zkHost.isBlank()) {
+        var zkSolrConnection = 
CloudSolrClient.CloudSolrClientConnection.parse(zkHost);
+        if (!zkSolrConnection.isZookeeper()) {
+          throw new IOException(
+              String.format(
+                  Locale.ROOT, "Expected ZooKeeper connection string, but got: 
'%s'.", zkHost));
+        }
+        solrUrl = solrUrlFromConnection(zkSolrConnection, credentials);
+      } else {
+        solrUrl = getDefaultSolrUrl();
+        CLIO.err(
+            "Neither --solr-connection, --zk-host or --solr-url parameters, 
nor SOLR_CONNECTION, ZK_HOST env var provided, so assuming solr url is "
+                + solrUrl
+                + ".");
+      }
+    }
+    return normalizeSolrUrl(solrUrl);
+  }
+
   /**
    * Resolves a base Solr URL from a parsed connection. The HTTP form (e.g. 
{@code -s
    * http://host:port}) already names a Solr URL, so it is used directly 
without spinning up a
diff --git a/solr/core/src/java/org/apache/solr/cli/CollectionNameOptions.java 
b/solr/core/src/java/org/apache/solr/cli/CollectionNameOptions.java
new file mode 100644
index 00000000000..975ef0708e2
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/CollectionNameOptions.java
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import picocli.CommandLine;
+
+/**
+ * Picocli mixin for the {@code -c} / {@code --name} option naming the 
collection a command acts on.
+ */
+class CollectionNameOptions {
+
+  @CommandLine.Option(
+      names = {"-c", "--name"},
+      required = true,
+      paramLabel = "NAME",
+      description = "Name of the collection.")
+  String name;
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotCreateShim.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateShim.java
new file mode 100644
index 00000000000..22b55a6da09
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateShim.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import org.apache.solr.logging.DeprecationLog;
+
+/**
+ * The old top-level {@code snapshot-create} spelling of {@code bin/solr 
snapshot create}, kept so
+ * that existing scripts keep working. It is hidden from help and the 
reference guide.
+ *
+ * @deprecated Use {@code bin/solr snapshot create}; this spelling is removed 
in Solr 11.
+ */
+@Deprecated(since = "10.2")
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "snapshot-create",
+    hidden = true,
+    description = "Deprecated; use 'snapshot create'.")
+public class SnapshotCreateShim extends SnapshotCreateTool {
+
+  @Override
+  public int callTool() throws Exception {
+    DeprecationLog.log(
+        "cli.snapshot-create",
+        "'bin/solr snapshot-create' is deprecated and will be removed in Solr 
11; use 'bin/solr snapshot create'.");
+    return super.callTool();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
index 89263c9da2c..5066f75f3bb 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
@@ -24,8 +24,22 @@ import 
org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.response.CollectionAdminResponse;
 
 /** Supports snapshot-create command in the bin/solr script. */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "create",
+    description = "Creates a named snapshot of a collection.",
+    footerHeading = "%nExamples:%n",
+    footer = {
+      "  # Create a snapshot",
+      "  bin/solr snapshot create -c mycollection --snapshot-name snap1"
+    })
 public class SnapshotCreateTool extends ToolBase {
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option COLLECTION_NAME_OPTION =
       Option.builder("c")
           .longOpt("name")
@@ -35,6 +49,11 @@ public class SnapshotCreateTool extends ToolBase {
           .desc("Name of collection to be snapshot.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option SNAPSHOT_NAME_OPTION =
       Option.builder()
           .longOpt("snapshot-name")
@@ -48,6 +67,21 @@ public class SnapshotCreateTool extends ToolBase {
   record SnapshotCreateParams(
       String solrUrl, String credentials, String collectionName, String 
snapshotName) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1")
+  private ConnectionOptions connectionOptions;
+
+  @picocli.CommandLine.Mixin private CredentialsOptions credentialsOptions;
+
+  @picocli.CommandLine.Mixin private CollectionNameOptions collection;
+
+  @picocli.CommandLine.Mixin private SnapshotNameOptions snapshot;
+
+  public SnapshotCreateTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public SnapshotCreateTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -112,6 +146,13 @@ public class SnapshotCreateTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    SnapshotCreateParams params =
+        new SnapshotCreateParams(
+            CLIUtils.resolveSolrUrl(connectionOptions, 
credentialsOptions.credentials),
+            credentialsOptions.credentials,
+            collection.name,
+            snapshot.name);
+    createSnapshot(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteShim.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteShim.java
new file mode 100644
index 00000000000..9834a17d668
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteShim.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import org.apache.solr.logging.DeprecationLog;
+
+/**
+ * The old top-level {@code snapshot-delete} spelling of {@code bin/solr 
snapshot delete}, kept so
+ * that existing scripts keep working. It is hidden from help and the 
reference guide.
+ *
+ * @deprecated Use {@code bin/solr snapshot delete}; this spelling is removed 
in Solr 11.
+ */
+@Deprecated(since = "10.2")
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "snapshot-delete",
+    hidden = true,
+    description = "Deprecated; use 'snapshot delete'.")
+public class SnapshotDeleteShim extends SnapshotDeleteTool {
+
+  @Override
+  public int callTool() throws Exception {
+    DeprecationLog.log(
+        "cli.snapshot-delete",
+        "'bin/solr snapshot-delete' is deprecated and will be removed in Solr 
11; use 'bin/solr snapshot delete'.");
+    return super.callTool();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
index 7ff35e5e95a..399796c9835 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
@@ -24,8 +24,22 @@ import 
org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.response.CollectionAdminResponse;
 
 /** Supports snapshot-delete command in the bin/solr script. */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "delete",
+    description = "Deletes a named snapshot of a collection.",
+    footerHeading = "%nExamples:%n",
+    footer = {
+      "  # Delete a snapshot",
+      "  bin/solr snapshot delete -c mycollection --snapshot-name snap1"
+    })
 public class SnapshotDeleteTool extends ToolBase {
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option COLLECTION_NAME_OPTION =
       Option.builder("c")
           .longOpt("name")
@@ -35,6 +49,11 @@ public class SnapshotDeleteTool extends ToolBase {
           .desc("Name of collection to manage.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option SNAPSHOT_NAME_OPTION =
       Option.builder()
           .longOpt("snapshot-name")
@@ -48,6 +67,21 @@ public class SnapshotDeleteTool extends ToolBase {
   record SnapshotDeleteParams(
       String solrUrl, String credentials, String collectionName, String 
snapshotName) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1")
+  private ConnectionOptions connectionOptions;
+
+  @picocli.CommandLine.Mixin private CredentialsOptions credentialsOptions;
+
+  @picocli.CommandLine.Mixin private CollectionNameOptions collection;
+
+  @picocli.CommandLine.Mixin private SnapshotNameOptions snapshot;
+
+  public SnapshotDeleteTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public SnapshotDeleteTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -112,6 +146,13 @@ public class SnapshotDeleteTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    SnapshotDeleteParams params =
+        new SnapshotDeleteParams(
+            CLIUtils.resolveSolrUrl(connectionOptions, 
credentialsOptions.credentials),
+            credentialsOptions.credentials,
+            collection.name,
+            snapshot.name);
+    deleteSnapshot(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeShim.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeShim.java
new file mode 100644
index 00000000000..8426c875484
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeShim.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import org.apache.solr.logging.DeprecationLog;
+
+/**
+ * The old top-level {@code snapshot-describe} spelling of {@code bin/solr 
snapshot describe}, kept
+ * so that existing scripts keep working. It is hidden from help and the 
reference guide.
+ *
+ * @deprecated Use {@code bin/solr snapshot describe}; this spelling is 
removed in Solr 11.
+ */
+@Deprecated(since = "10.2")
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "snapshot-describe",
+    hidden = true,
+    description = "Deprecated; use 'snapshot describe'.")
+public class SnapshotDescribeShim extends SnapshotDescribeTool {
+
+  @Override
+  public int callTool() throws Exception {
+    DeprecationLog.log(
+        "cli.snapshot-describe",
+        "'bin/solr snapshot-describe' is deprecated and will be removed in 
Solr 11; use 'bin/solr snapshot describe'.");
+    return super.callTool();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
index d945c23d57f..9793903ccfc 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
@@ -34,8 +34,22 @@ import 
org.apache.solr.core.snapshots.CollectionSnapshotMetaData;
 import org.apache.solr.core.snapshots.SolrSnapshotManager;
 
 /** Supports snapshot-describe command in the bin/solr script. */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "describe",
+    description = "Describes a named snapshot of a collection.",
+    footerHeading = "%nExamples:%n",
+    footer = {
+      "  # Describe a snapshot",
+      "  bin/solr snapshot describe -c mycollection --snapshot-name snap1"
+    })
 public class SnapshotDescribeTool extends ToolBase {
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option COLLECTION_NAME_OPTION =
       Option.builder("c")
           .longOpt("name")
@@ -45,6 +59,11 @@ public class SnapshotDescribeTool extends ToolBase {
           .desc("Name of collection to be snapshot.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option SNAPSHOT_NAME_OPTION =
       Option.builder()
           .longOpt("snapshot-name")
@@ -58,6 +77,21 @@ public class SnapshotDescribeTool extends ToolBase {
   record SnapshotDescribeParams(
       String solrUrl, String credentials, String collectionName, String 
snapshotName) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1")
+  private ConnectionOptions connectionOptions;
+
+  @picocli.CommandLine.Mixin private CredentialsOptions credentialsOptions;
+
+  @picocli.CommandLine.Mixin private CollectionNameOptions collection;
+
+  @picocli.CommandLine.Mixin private SnapshotNameOptions snapshot;
+
+  public SnapshotDescribeTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public SnapshotDescribeTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -151,6 +185,13 @@ public class SnapshotDescribeTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    SnapshotDescribeParams params =
+        new SnapshotDescribeParams(
+            CLIUtils.resolveSolrUrl(connectionOptions, 
credentialsOptions.credentials),
+            credentialsOptions.credentials,
+            collection.name,
+            snapshot.name);
+    describeSnapshot(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotExportShim.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotExportShim.java
new file mode 100644
index 00000000000..4cb77cf05f2
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotExportShim.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import org.apache.solr.logging.DeprecationLog;
+
+/**
+ * The old top-level {@code snapshot-export} spelling of {@code bin/solr 
snapshot export}, kept so
+ * that existing scripts keep working. It is hidden from help and the 
reference guide.
+ *
+ * @deprecated Use {@code bin/solr snapshot export}; this spelling is removed 
in Solr 11.
+ */
+@Deprecated(since = "10.2")
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "snapshot-export",
+    hidden = true,
+    description = "Deprecated; use 'snapshot export'.")
+public class SnapshotExportShim extends SnapshotExportTool {
+
+  @Override
+  public int callTool() throws Exception {
+    DeprecationLog.log(
+        "cli.snapshot-export",
+        "'bin/solr snapshot-export' is deprecated and will be removed in Solr 
11; use 'bin/solr snapshot export'.");
+    return super.callTool();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
index 8544122e261..06b8017c1ed 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
@@ -28,11 +28,25 @@ import 
org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.common.params.CollectionAdminParams;
 
 /** Supports snapshot-export command in the bin/solr script. */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "export",
+    description = "Backs up a collection's current state to a local 
directory.",
+    footerHeading = "%nExamples:%n",
+    footer = {
+      "  # Export a collection's current state as a backup",
+      "  bin/solr snapshot export -c mycollection --dest-dir /tmp/backups 
--backup-repo-name local"
+    })
 public class SnapshotExportTool extends ToolBase {
 
   private static final DateTimeFormatter BACKUP_NAME_TIMESTAMP =
       DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'", 
Locale.ROOT).withZone(ZoneOffset.UTC);
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option COLLECTION_NAME_OPTION =
       Option.builder("c")
           .longOpt("name")
@@ -46,6 +60,11 @@ public class SnapshotExportTool extends ToolBase {
    * Accepted only so that passing it can be rejected with an explanation. 
Selecting a named
    * snapshot to export required the non-incremental backup format, which no 
longer exists.
    */
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option SNAPSHOT_NAME_OPTION =
       Option.builder()
           .longOpt("snapshot-name")
@@ -54,6 +73,11 @@ public class SnapshotExportTool extends ToolBase {
           .desc("No longer supported; passing it fails with an error.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option DEST_DIR_OPTION =
       Option.builder()
           .longOpt("dest-dir")
@@ -63,6 +87,11 @@ public class SnapshotExportTool extends ToolBase {
           .desc("Path of a temporary directory on local filesystem during 
snapshot export command.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option BACKUP_REPO_NAME_OPTION =
       Option.builder()
           .longOpt("backup-repo-name")
@@ -72,6 +101,11 @@ public class SnapshotExportTool extends ToolBase {
               "Specifies name of the backup repository to be used during 
snapshot export preparation.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option ASYNC_ID_OPTION =
       Option.builder()
           .longOpt("async-id")
@@ -90,6 +124,48 @@ public class SnapshotExportTool extends ToolBase {
       String backupRepo,
       String asyncReqId) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1")
+  private ConnectionOptions connectionOptions;
+
+  @picocli.CommandLine.Mixin private CredentialsOptions credentialsOptions;
+
+  @picocli.CommandLine.Mixin private CollectionNameOptions collection;
+
+  // Accepted only so that passing it can be rejected with an explanation; see 
callTool().
+  @picocli.CommandLine.Option(
+      names = "--snapshot-name",
+      paramLabel = "NAME",
+      description = "No longer supported; passing it fails with an error.")
+  private String snapshotNameOpt;
+
+  @picocli.CommandLine.Option(
+      names = "--dest-dir",
+      required = true,
+      paramLabel = "DIR",
+      description =
+          "Path of a temporary directory on local filesystem during snapshot 
export command.")
+  private String destDirOpt;
+
+  @picocli.CommandLine.Option(
+      names = "--backup-repo-name",
+      paramLabel = "NAME",
+      description =
+          "Specifies name of the backup repository to be used during snapshot 
export preparation.")
+  private String backupRepoNameOpt;
+
+  @picocli.CommandLine.Option(
+      names = "--async-id",
+      paramLabel = "ID",
+      description =
+          "Specifies the async request identifier to be used during snapshot 
export preparation.")
+  private String asyncIdOpt;
+
+  public SnapshotExportTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public SnapshotExportTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -178,6 +254,21 @@ public class SnapshotExportTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    if (snapshotNameOpt != null) {
+      throw new IllegalArgumentException(
+          "--snapshot-name is no longer supported. Exporting a named snapshot 
required the "
+              + "non-incremental backup format, which was removed in Solr 11; 
this command now "
+              + "always backs up the collection's current state. Re-run 
without --snapshot-name.");
+    }
+    SnapshotExportParams params =
+        new SnapshotExportParams(
+            CLIUtils.resolveSolrUrl(connectionOptions, 
credentialsOptions.credentials),
+            credentialsOptions.credentials,
+            collection.name,
+            destDirOpt,
+            backupRepoNameOpt,
+            asyncIdOpt);
+    exportSnapshot(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotListShim.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotListShim.java
new file mode 100644
index 00000000000..4085ead8ff0
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotListShim.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import org.apache.solr.logging.DeprecationLog;
+
+/**
+ * The old top-level {@code snapshot-list} spelling of {@code bin/solr 
snapshot list}, kept so that
+ * existing scripts keep working. It is hidden from help and the reference 
guide.
+ *
+ * @deprecated Use {@code bin/solr snapshot list}; this spelling is removed in 
Solr 11.
+ */
+@Deprecated(since = "10.2")
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "snapshot-list",
+    hidden = true,
+    description = "Deprecated; use 'snapshot list'.")
+public class SnapshotListShim extends SnapshotListTool {
+
+  @Override
+  public int callTool() throws Exception {
+    DeprecationLog.log(
+        "cli.snapshot-list",
+        "'bin/solr snapshot-list' is deprecated and will be removed in Solr 
11; use 'bin/solr snapshot list'.");
+    return super.callTool();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
index a4d7ea3b56a..4649215b53e 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
@@ -26,8 +26,19 @@ import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.snapshots.SolrSnapshotManager;
 
 /** Supports snapshot-list command in the bin/solr script. */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "list",
+    description = "Lists the snapshots for a collection.",
+    footerHeading = "%nExamples:%n",
+    footer = {"  # List a collection's snapshots", "  bin/solr snapshot list 
-c mycollection"})
 public class SnapshotListTool extends ToolBase {
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option COLLECTION_NAME_OPTION =
       Option.builder("c")
           .longOpt("name")
@@ -40,6 +51,19 @@ public class SnapshotListTool extends ToolBase {
   /** Parameters for the snapshot-list command, independent of the command 
line parser. */
   record SnapshotListParams(String solrUrl, String credentials, String 
collectionName) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1")
+  private ConnectionOptions connectionOptions;
+
+  @picocli.CommandLine.Mixin private CredentialsOptions credentialsOptions;
+
+  @picocli.CommandLine.Mixin private CollectionNameOptions collection;
+
+  public SnapshotListTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public SnapshotListTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -99,6 +123,12 @@ public class SnapshotListTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    SnapshotListParams params =
+        new SnapshotListParams(
+            CLIUtils.resolveSolrUrl(connectionOptions, 
credentialsOptions.credentials),
+            credentialsOptions.credentials,
+            collection.name);
+    listSnapshots(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotNameOptions.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotNameOptions.java
new file mode 100644
index 00000000000..c4a95de9976
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotNameOptions.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import picocli.CommandLine;
+
+/** Picocli mixin for the {@code --snapshot-name} option shared by the 
snapshot sub-commands. */
+class SnapshotNameOptions {
+
+  @CommandLine.Option(
+      names = "--snapshot-name",
+      required = true,
+      paramLabel = "NAME",
+      description = "Name of the snapshot.")
+  String name;
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotTool.java 
b/solr/core/src/java/org/apache/solr/cli/SnapshotTool.java
new file mode 100644
index 00000000000..6c7aba2e33a
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotTool.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import java.util.concurrent.Callable;
+import picocli.CommandLine;
+
+/**
+ * Sub commands for working with collection snapshots, only here to provide a 
common parent for the
+ * subcommands and print tool help.
+ */
[email protected](
+    name = "snapshot",
+    description = "Sub commands for working with collection snapshots.",
+    footer = "\nPass --help or -h after any COMMAND to see command-specific 
usage information.",
+    subcommands = {
+      SnapshotCreateTool.class,
+      SnapshotDeleteTool.class,
+      SnapshotDescribeTool.class,
+      SnapshotExportTool.class,
+      SnapshotListTool.class
+    })
+public class SnapshotTool implements Callable<Integer> {
+  @CommandLine.Mixin HelpMixin helpMixin;
+  @CommandLine.Spec CommandLine.Model.CommandSpec spec;
+
+  @Override
+  public Integer call() {
+    spec.commandLine().usage(CLIO.getOutStream());
+    return 0;
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java 
b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
index 4f2c27d6681..f1936cf8d68 100755
--- a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
@@ -89,7 +89,13 @@ import org.slf4j.LoggerFactory;
       HealthcheckTool.class,
       PostTool.class,
       PostLogsTool.class,
-      StreamTool.class
+      StreamTool.class,
+      SnapshotTool.class,
+      SnapshotCreateShim.class,
+      SnapshotDeleteShim.class,
+      SnapshotDescribeShim.class,
+      SnapshotExportShim.class,
+      SnapshotListShim.class
     })
 public class SolrCLI implements CLIO, java.util.concurrent.Callable<Integer> {
 
diff --git 
a/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolPicocliTest.java 
b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolPicocliTest.java
new file mode 100644
index 00000000000..8be7c47e459
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolPicocliTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.solr.cli;
+
+/**
+ * Runs the {@link SnapshotExportToolTest} tests that go through {@code 
runTool} using the {@code
+ * bin/solr snapshot export} sub-command; the tests that call the commons-cli 
parser directly are
+ * inherited and run unchanged.
+ */
+public class SnapshotExportToolPicocliTest extends SnapshotExportToolTest {
+
+  @Override
+  protected int runTool(
+      String[] args, CLITestHelper.TestingRuntime runtime, Class<? extends 
ToolBase> clazz)
+      throws Exception {
+    return SnapshotToolsPicocliTest.runAsGroup(args, runtime);
+  }
+}
diff --git a/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java 
b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
index 81c46f302dd..a3c45246a10 100644
--- a/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
+++ b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
@@ -37,6 +37,13 @@ import org.junit.Test;
 @LuceneTestCase.SuppressCodecs({"SimpleText"})
 public class SnapshotExportToolTest extends SolrCloudTestCase {
 
+  /** Runs the tool. Overridden by the picocli variant of this test. */
+  protected int runTool(
+      String[] args, CLITestHelper.TestingRuntime runtime, Class<? extends 
ToolBase> clazz)
+      throws Exception {
+    return CLITestHelper.runTool(args, runtime, clazz);
+  }
+
   private static final String COLLECTION = "snapshot_export_coll";
 
   @BeforeClass
@@ -124,6 +131,29 @@ public class SnapshotExportToolTest extends 
SolrCloudTestCase {
         Arrays.stream(cli.getOptions()).anyMatch(o -> 
"snapshot-name".equals(o.getLongOpt())));
   }
 
+  /** Whichever parser runs, the option is refused with an error exit and 
nothing is written. */
+  @Test
+  public void testSnapshotNameIsRefusedWithAnErrorExit() throws Exception {
+    Path destDir = newDestDir();
+    int exitCode =
+        runTool(
+            new String[] {
+              "snapshot-export",
+              "-c",
+              COLLECTION,
+              "--dest-dir",
+              destDir.toString(),
+              "--solr-url",
+              solrUrl(),
+              "--snapshot-name",
+              "snap1"
+            },
+            new CLITestHelper.TestingRuntime(false),
+            SnapshotExportTool.class);
+    assertEquals(1, exitCode);
+    assertEquals(List.of(), backupDirs(destDir));
+  }
+
   @Test
   public void testBackupNameIsDerivedFromCollectionAndTime() {
     assertEquals(
@@ -137,7 +167,7 @@ public class SnapshotExportToolTest extends 
SolrCloudTestCase {
     Path destDir = newDestDir();
     CLITestHelper.TestingRuntime runtime = new 
CLITestHelper.TestingRuntime(true);
     int exitCode =
-        CLITestHelper.runTool(
+        runTool(
             new String[] {
               "snapshot-export",
               "-c",
diff --git 
a/solr/core/src/test/org/apache/solr/cli/SnapshotToolsPicocliTest.java 
b/solr/core/src/test/org/apache/solr/cli/SnapshotToolsPicocliTest.java
new file mode 100644
index 00000000000..649c5185cf9
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cli/SnapshotToolsPicocliTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.solr.logging.DeprecationLog;
+import org.apache.solr.util.LogListener;
+import org.junit.Test;
+import picocli.CommandLine;
+
+/**
+ * Runs {@link SnapshotToolsTest} through picocli, using the {@code bin/solr 
snapshot <sub-command>}
+ * group, and checks that the old {@code snapshot-*} spellings still work as 
hidden, deprecated
+ * shims.
+ */
+public class SnapshotToolsPicocliTest extends SnapshotToolsTest {
+
+  /**
+   * Builds the real root command, giving each tool the test's runtime so its 
output is captured.
+   */
+  private static CommandLine root(CLITestHelper.TestingRuntime runtime) {
+    CommandLine.IFactory factory =
+        new CommandLine.IFactory() {
+          @Override
+          public <K> K create(Class<K> cls) throws Exception {
+            if (ToolBase.class.isAssignableFrom(cls)) {
+              try {
+                return 
cls.getDeclaredConstructor(ToolRuntime.class).newInstance(runtime);
+              } catch (NoSuchMethodException e) {
+                // a shim: it has only the default constructor
+              }
+            }
+            return CommandLine.defaultFactory().create(cls);
+          }
+        };
+    return new CommandLine(new SolrCLI(), factory);
+  }
+
+  /** Runs a commons-cli style {@code snapshot-<x> ...} command line as {@code 
snapshot <x> ...}. */
+  static int runAsGroup(String[] args, CLITestHelper.TestingRuntime runtime) {
+    List<String> grouped =
+        new ArrayList<>(List.of("snapshot", 
args[0].substring("snapshot-".length())));
+    grouped.addAll(List.of(args).subList(1, args.length));
+    return root(runtime).execute(grouped.toArray(new String[0]));
+  }
+
+  @Override
+  protected int runTool(
+      String[] args, CLITestHelper.TestingRuntime runtime, Class<? extends 
ToolBase> clazz)
+      throws Exception {
+    return runAsGroup(args, runtime);
+  }
+
+  @Test
+  public void testConnectionFallsBackToTheSolrConnectionProperty() throws 
Exception {
+    // SOLR_CONNECTION reaches the JVM as the solr.connection property
+    run(SnapshotCreateTool.class, "snapshot-create", "--snapshot-name", 
"snapViaConnection");
+
+    System.setProperty("solr.connection", 
cluster.getZkClient().getZkServerAddress());
+    CLITestHelper.TestingRuntime runtime = new 
CLITestHelper.TestingRuntime(true);
+    assertEquals(
+        0,
+        runTool(new String[] {"snapshot-list", "-c", COLLECTION}, runtime, 
SnapshotListTool.class));
+    assertTrue(runtime.getOutput(), 
runtime.getOutput().contains("snapViaConnection"));
+    run(SnapshotDeleteTool.class, "snapshot-delete", "--snapshot-name", 
"snapViaConnection");
+  }
+
+  @Test
+  public void testOldSpellingsStillWork() throws Exception {
+    CommandLine root = root(new CLITestHelper.TestingRuntime(true));
+    String url = cluster.getJettySolrRunner(0).getBaseUrl().toString();
+
+    // the notice is logged once per JVM, and this is the only test that runs 
the old spellings
+    try (LogListener deprecation =
+        LogListener.warn(DeprecationLog.LOG_PREFIX + "cli.snapshot-create")) {
+      assertEquals(
+          0,
+          root.execute(
+              "snapshot-create",
+              "-c",
+              COLLECTION,
+              "--snapshot-name",
+              "oldSpelling",
+              "--solr-url",
+              url));
+      String notice = deprecation.pollMessage();
+      assertNotNull("a deprecation notice is logged", notice);
+      assertTrue(notice, notice.contains("bin/solr snapshot create"));
+    }
+    assertTrue(run(SnapshotListTool.class, 
"snapshot-list").contains("oldSpelling"));
+    assertEquals(
+        0,
+        root.execute(
+            "snapshot-delete",
+            "-c",
+            COLLECTION,
+            "--snapshot-name",
+            "oldSpelling",
+            "--solr-url",
+            url));
+    assertFalse(run(SnapshotListTool.class, 
"snapshot-list").contains("oldSpelling"));
+  }
+
+  /** Goes with the shims, which are removed in Solr 11. */
+  @Deprecated
+  @Test
+  public void testOldSpellingsAreHiddenAndDeprecated() {
+    CommandLine root = root(new CLITestHelper.TestingRuntime(true));
+    for (String sub : List.of("create", "delete", "describe", "export", 
"list")) {
+      CommandLine shim = root.getSubcommands().get("snapshot-" + sub);
+      assertNotNull("snapshot-" + sub, shim);
+      assertTrue("snapshot-" + sub, 
shim.getCommandSpec().usageMessage().hidden());
+      Deprecated deprecated = 
shim.getCommand().getClass().getAnnotation(Deprecated.class);
+      assertNotNull("snapshot-" + sub, deprecated);
+      assertEquals("10.2", deprecated.since());
+    }
+    assertFalse(root.getUsageMessage().contains("snapshot-create"));
+    assertTrue(root.getUsageMessage().contains("snapshot"));
+  }
+
+  @Test
+  public void testGroupListsItsSubCommands() {
+    String usage =
+        root(new CLITestHelper.TestingRuntime(true))
+            .getSubcommands()
+            .get("snapshot")
+            .getUsageMessage();
+    for (String sub : List.of("create", "delete", "describe", "export", 
"list")) {
+      assertTrue(sub + " in " + usage, usage.contains(sub));
+    }
+  }
+}
diff --git a/solr/core/src/test/org/apache/solr/cli/SnapshotToolsTest.java 
b/solr/core/src/test/org/apache/solr/cli/SnapshotToolsTest.java
new file mode 100644
index 00000000000..5389dfe1573
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cli/SnapshotToolsTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.apache.solr.cli;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/** The snapshot-create, -list, -describe and -delete commands through the 
command line. */
+public class SnapshotToolsTest extends SolrCloudTestCase {
+  static final String COLLECTION = "snapshotToolsColl";
+
+  /** Runs the tool. Overridden by the picocli variant of this test. */
+  protected int runTool(
+      String[] args, CLITestHelper.TestingRuntime runtime, Class<? extends 
ToolBase> clazz)
+      throws Exception {
+    return CLITestHelper.runTool(args, runtime, clazz);
+  }
+
+  @BeforeClass
+  public static void setupCluster() throws Exception {
+    configureCluster(1).addConfig("conf", 
configset("cloud-minimal")).configure();
+    CollectionAdminRequest.createCollection(COLLECTION, "conf", 1, 1)
+        .process(cluster.getSolrClient());
+    cluster.waitForActiveCollection(COLLECTION, 1, 1);
+    cluster.getSolrClient().add(COLLECTION, new SolrInputDocument("id", "1"));
+    cluster.getSolrClient().commit(COLLECTION);
+  }
+
+  String run(Class<? extends ToolBase> tool, String name, String... extra) 
throws Exception {
+    List<String> args =
+        new ArrayList<>(
+            List.of(
+                name,
+                "-c",
+                COLLECTION,
+                "--solr-url",
+                cluster.getJettySolrRunner(0).getBaseUrl().toString()));
+    args.addAll(List.of(extra));
+    CLITestHelper.TestingRuntime runtime = new 
CLITestHelper.TestingRuntime(true);
+    assertEquals(0, runTool(args.toArray(new String[0]), runtime, tool));
+    return runtime.getOutput();
+  }
+
+  @Test
+  public void testSnapshotLifecycle() throws Exception {
+    run(SnapshotCreateTool.class, "snapshot-create", "--snapshot-name", 
"snap1");
+
+    assertTrue(run(SnapshotListTool.class, "snapshot-list").contains("snap1"));
+
+    String described =
+        run(SnapshotDescribeTool.class, "snapshot-describe", 
"--snapshot-name", "snap1");
+    assertTrue(described, described.contains("Name: snap1"));
+
+    run(SnapshotDeleteTool.class, "snapshot-delete", "--snapshot-name", 
"snap1");
+
+    assertFalse(run(SnapshotListTool.class, 
"snapshot-list").contains("snap1"));
+  }
+
+  // snapshot-list reports a failed request in its output and still exits 0, 
so check the output.
+  @Test
+  public void testConnectionFallsBackToTheZkHostProperty() throws Exception {
+    run(SnapshotCreateTool.class, "snapshot-create", "--snapshot-name", 
"snapViaProperty");
+
+    System.setProperty("zkHost", cluster.getZkClient().getZkServerAddress());
+    CLITestHelper.TestingRuntime runtime = new 
CLITestHelper.TestingRuntime(true);
+    assertEquals(
+        0,
+        runTool(new String[] {"snapshot-list", "-c", COLLECTION}, runtime, 
SnapshotListTool.class));
+    assertTrue(runtime.getOutput(), 
runtime.getOutput().contains("snapViaProperty"));
+    run(SnapshotDeleteTool.class, "snapshot-delete", "--snapshot-name", 
"snapViaProperty");
+  }
+}
diff --git a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
index 074440d2a99..034346e499d 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
@@ -31,6 +31,12 @@
 *** xref:cli/solr-healthcheck.adoc[healthcheck]
 *** xref:cli/solr-post.adoc[post]
 *** xref:cli/solr-postlogs.adoc[postlogs]
+*** xref:cli/solr-snapshot.adoc[snapshot]
+**** xref:cli/solr-snapshot-create.adoc[create]
+**** xref:cli/solr-snapshot-delete.adoc[delete]
+**** xref:cli/solr-snapshot-describe.adoc[describe]
+**** xref:cli/solr-snapshot-export.adoc[export]
+**** xref:cli/solr-snapshot-list.adoc[list]
 *** xref:cli/solr-start.adoc[start]
 *** xref:cli/solr-status.adoc[status]
 *** xref:cli/solr-stop.adoc[stop]
diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
index e7e950ea5e1..4dbe2b5dea4 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
@@ -70,6 +70,12 @@ Any command not listed here is unavailable when the picocli 
implementation is en
 |xref:cli/solr-healthcheck.adoc[bin/solr healthcheck]
 |xref:cli/solr-post.adoc[bin/solr post]
 |xref:cli/solr-postlogs.adoc[bin/solr postlogs]
+|xref:cli/solr-snapshot-create.adoc[bin/solr snapshot create]
+|xref:cli/solr-snapshot-delete.adoc[bin/solr snapshot delete]
+|xref:cli/solr-snapshot-describe.adoc[bin/solr snapshot describe]
+|xref:cli/solr-snapshot-export.adoc[bin/solr snapshot export]
+|xref:cli/solr-snapshot-list.adoc[bin/solr snapshot list]
+|xref:cli/solr-snapshot.adoc[bin/solr snapshot]
 |xref:cli/solr-start.adoc[bin/solr start]
 |xref:cli/solr-status.adoc[bin/solr status]
 |xref:cli/solr-stop.adoc[bin/solr stop]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-create.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-create.adoc
new file mode 100644
index 00000000000..e4b1b14c008
--- /dev/null
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-create.adoc
@@ -0,0 +1,84 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot create
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot create [-hv] -c=NAME --snapshot-name=NAME [-u=<credentials>]
+                         [-s=<solrConnection> | --solr-url=<solrUrl> | 
-z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Creates a named snapshot of a collection.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-c*, *--name*=_NAME_::
+  *(required)* Name of the collection.
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--snapshot-name*=_NAME_::
+  *(required)* Name of the snapshot.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if that's not 
known.
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # Create a snapshot
+  bin/solr snapshot create -c mycollection --snapshot-name snap1
+
+// end::picocli-generated-man-section-footer[]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-delete.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-delete.adoc
new file mode 100644
index 00000000000..eadf9e84b7c
--- /dev/null
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-delete.adoc
@@ -0,0 +1,84 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot delete
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot delete [-hv] -c=NAME --snapshot-name=NAME [-u=<credentials>]
+                         [-s=<solrConnection> | --solr-url=<solrUrl> | 
-z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Deletes a named snapshot of a collection.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-c*, *--name*=_NAME_::
+  *(required)* Name of the collection.
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--snapshot-name*=_NAME_::
+  *(required)* Name of the snapshot.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if that's not 
known.
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # Delete a snapshot
+  bin/solr snapshot delete -c mycollection --snapshot-name snap1
+
+// end::picocli-generated-man-section-footer[]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-describe.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-describe.adoc
new file mode 100644
index 00000000000..11e6a1a31ce
--- /dev/null
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-describe.adoc
@@ -0,0 +1,85 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot describe
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot describe [-hv] -c=NAME --snapshot-name=NAME 
[-u=<credentials>]
+                           [-s=<solrConnection> | --solr-url=<solrUrl> |
+                           -z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Describes a named snapshot of a collection.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-c*, *--name*=_NAME_::
+  *(required)* Name of the collection.
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--snapshot-name*=_NAME_::
+  *(required)* Name of the snapshot.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if that's not 
known.
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # Describe a snapshot
+  bin/solr snapshot describe -c mycollection --snapshot-name snap1
+
+// end::picocli-generated-man-section-footer[]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-export.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-export.adoc
new file mode 100644
index 00000000000..606617e3f3c
--- /dev/null
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-export.adoc
@@ -0,0 +1,94 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot export
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot export [-hv] [--async-id=ID] [--backup-repo-name=NAME] 
-c=NAME
+                         --dest-dir=DIR [--snapshot-name=NAME] 
[-u=<credentials>]
+                         [-s=<solrConnection> | --solr-url=<solrUrl> | 
-z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Backs up a collection's current state to a local directory.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*--async-id*=_ID_::
+  Specifies the async request identifier to be used during snapshot export 
preparation.
+
+*--backup-repo-name*=_NAME_::
+  Specifies name of the backup repository to be used during snapshot export 
preparation.
+
+*-c*, *--name*=_NAME_::
+  *(required)* Name of the collection.
+
+*--dest-dir*=_DIR_::
+  *(required)* Path of a temporary directory on local filesystem during 
snapshot export command.
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--snapshot-name*=_NAME_::
+  No longer supported; passing it fails with an error.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if that's not 
known.
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # Export a collection's current state as a backup
+  bin/solr snapshot export -c mycollection --dest-dir /tmp/backups 
--backup-repo-name local
+
+// end::picocli-generated-man-section-footer[]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-list.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-list.adoc
new file mode 100644
index 00000000000..d0139e4520a
--- /dev/null
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot-list.adoc
@@ -0,0 +1,81 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot list
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot list [-hv] -c=NAME [-u=<credentials>] [-s=<solrConnection> |
+                       --solr-url=<solrUrl> | -z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Lists the snapshots for a collection.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-c*, *--name*=_NAME_::
+  *(required)* Name of the collection.
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if that's not 
known.
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # List a collection's snapshots
+  bin/solr snapshot list -c mycollection
+
+// end::picocli-generated-man-section-footer[]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot.adoc
new file mode 100644
index 00000000000..f0b674d0678
--- /dev/null
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-snapshot.adoc
@@ -0,0 +1,74 @@
+// 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr snapshot
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr snapshot [-h] [COMMAND]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Sub commands for working with collection snapshots.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-commands[]
+== Commands
+
+xref:cli/solr-snapshot-create.adoc[*create*]::
+  Creates a named snapshot of a collection.
+
+xref:cli/solr-snapshot-delete.adoc[*delete*]::
+  Deletes a named snapshot of a collection.
+
+xref:cli/solr-snapshot-describe.adoc[*describe*]::
+  Describes a named snapshot of a collection.
+
+xref:cli/solr-snapshot-export.adoc[*export*]::
+  Backs up a collection's current state to a local directory.
+
+xref:cli/solr-snapshot-list.adoc[*list*]::
+  Lists the snapshots for a collection.
+
+// end::picocli-generated-man-section-commands[]
diff --git 
a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc 
b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc
index 3a5a236542a..d8450340a57 100644
--- 
a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc
+++ 
b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc
@@ -34,6 +34,22 @@ This compatibility safeguard can be disabled via the 
environment variable `SOLR_
 
 Solr 10.0 requires at least Java 21, while SolrJ 10.0 requires at least Java 
17.
 
+== Solr 10.2
+
+=== Snapshot commands are now `bin/solr snapshot` sub-commands
+
+The `snapshot-create`, `snapshot-delete`, `snapshot-describe`, 
`snapshot-export` and `snapshot-list` commands of the experimental picocli 
command line interface are replaced by the sub-commands of `bin/solr snapshot`:
+
+[source,bash]
+----
+bin/solr snapshot create -c mycollection --snapshot-name snap1
+bin/solr snapshot list -c mycollection
+----
+
+The old spellings still work and are hidden from the help and from this guide.
+They are deprecated in Solr 10.2 and are removed in Solr 11.0.
+The default command line interface is not changed.
+
 == Solr 10.1
 
 === Misc

Reply via email to