<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Clojure Q&amp;A - Recent activity in tools.cli</title>
<link>https://ask.clojure.org/index.php/activity/contrib-libs/tools-cli</link>
<description></description>
<item>
<title>Closed: tools.cli: capture unrecognized options as unparsed arguments</title>
<link>https://ask.clojure.org/index.php/14977/tools-cli-capture-unrecognized-options-unparsed-arguments?show=14977#q14977</link>
<description>&lt;p&gt;I frequently write a command that accepts options and in turn execute a shell command passing arguments through; I want to be able to specify additional arguments to that shell command.&lt;/p&gt;
&lt;p&gt;In tools.cli, the :in-order key &lt;em&gt;almost&lt;/em&gt; does what i want:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;`&lt;/code&gt;&lt;br&gt;
(require '[clojure.tools.cli :as cli])&lt;br&gt;
=&amp;gt; nil&lt;br&gt;
(def opts [[&quot;-d&quot; &quot;--debug&quot;]])&lt;br&gt;
=&amp;gt; #'net.lewisship.cli-tools-test/opts&lt;br&gt;
(cli/parse-opts&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&quot;--foo&quot;]
[]
:in-order true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;=&amp;gt; {:options {}, :arguments [], :summary &quot;&quot;, :errors [&quot;Unknown option: \&quot;--foo\&quot;&quot;]}&lt;br&gt;
(cli/parse-opts&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&quot;xxx&quot; &quot;--foo&quot;]
[]
:in-order true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;=&amp;gt; {:options {}, :arguments [&quot;xxx&quot; &quot;--foo&quot;], :summary &quot;&quot;, :errors nil}&lt;br&gt;
&lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;However, it will assume an undefined option is an error until the first non-option argument is consumed.&lt;/p&gt;
&lt;p&gt;I would like a further option that is like :in-order but accepting of these unrecognized options.  Maybe, :passthru-options would be a good name?&lt;/p&gt;
&lt;p&gt;I can work on a patch if we have some consensus on direction.&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14977/tools-cli-capture-unrecognized-options-unparsed-arguments?show=14977#q14977</guid>
<pubDate>Tue, 10 Mar 2026 16:08:38 +0000</pubDate>
</item>
<item>
<title>Closed: Review cli-matic for inspiration for enhancing tools.cli</title>
<link>https://ask.clojure.org/index.php/7812/review-cli-matic-for-inspiration-for-enhancing-tools-cli?show=7812#q7812</link>
<description>&lt;p&gt;See &lt;a rel=&quot;nofollow&quot; href=&quot;https://cljdoc.org/d/cli-matic/cli-matic/0.2.7/doc/readme&quot;&gt;https://cljdoc.org/d/cli-matic/cli-matic/0.2.7/doc/readme&lt;/a&gt;&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/7812/review-cli-matic-for-inspiration-for-enhancing-tools-cli?show=7812#q7812</guid>
<pubDate>Fri, 06 Mar 2026 01:06:24 +0000</pubDate>
</item>
<item>
<title>Closed: Tools.cli :validate: provide a way to post-validate (after updates)</title>
<link>https://ask.clojure.org/index.php/10267/tools-cli-validate-provide-way-post-validate-after-updates?show=10267#q10267</link>
<description>&lt;p&gt;aratare on Slack had this code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&quot;-v&quot; nil &quot;Verbosity level; may be specified up to 2 times. Levels: INFO (Default) -&amp;gt; DEBUG -&amp;gt; TRACE&quot;
    ;; If no long-option is specified, an option :id must be given
    :id :min-level
    :default 0
    :update-fn inc
    :validate [(fn [a]
                 (println a)
                 (&amp;lt;= a 2)) &quot;Verbosity level cannot exceed 2.&quot;]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and asked:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;and &lt;code&gt;a&lt;/code&gt; is printed as &lt;code&gt;true&lt;/code&gt; instead of either the level before or after applying &lt;code&gt;update-fn&lt;/code&gt;. Is there a way to work around this so I can validate after &lt;code&gt;update-fn&lt;/code&gt; has been called? Thanks in advance. (edited) &lt;/p&gt;
&lt;/blockquote&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/10267/tools-cli-validate-provide-way-post-validate-after-updates?show=10267#q10267</guid>
<pubDate>Fri, 06 Mar 2026 01:05:21 +0000</pubDate>
</item>
<item>
<title>Closed: Tools.cli :validate: provide function of invalid value in addition to fixed string</title>
<link>https://ask.clojure.org/index.php/10265/tools-validate-provide-function-invalid-value-addition-string?show=10265#q10265</link>
<description>&lt;p&gt;The &lt;code&gt;:validate&lt;/code&gt; option currently takes a validation function and a string error message.&lt;/p&gt;
&lt;p&gt;Could we extend the second argument to a function instead so you can return an error message like &lt;code&gt;&quot;--foo should be greater than 10, but was: 11&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We could even plug &lt;code&gt;clojure.spec.alpha&lt;/code&gt; or &lt;code&gt;malli&lt;/code&gt; in there:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(def cli-options
  [[&quot;-n&quot; &quot;--number NUM&quot; &quot;A number&quot;
    :parse-fn (m/decoder int? mt/string-transformer)
    :validate [(fn [input]
                 (m/validate [:&amp;lt; 100] input))
               (fn [input]
                 (me/humanize (m/explain [:&amp;lt; 100] input)))]]])
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/10265/tools-validate-provide-function-invalid-value-addition-string?show=10265#q10265</guid>
<pubDate>Fri, 06 Mar 2026 01:04:56 +0000</pubDate>
</item>
<item>
<title>Closed: tools.cli: display default value for --[no-]foo flags in help summary</title>
<link>https://ask.clojure.org/index.php/12069/tools-cli-display-default-value-for-no-foo-flags-help-summary?show=12069#q12069</link>
<description>&lt;p&gt;Salut&lt;/p&gt;
&lt;p&gt;While boolean options of the form &quot;--foo&quot; are false by default and enabled by specifying them, flag options of the form &quot;--[no-]foo&quot; accept &quot;--foo&quot; and &quot;--no-foo&quot; to toggle them on or off respectively. The default could be true or false, but the user has no way to tell what the default value is based on the help summary.&lt;/p&gt;
&lt;p&gt;For those options I think it is helpful (even necessary) to always display the default value, whether the option is required or not.&lt;/p&gt;
&lt;p&gt;I've drafted a patch that could serve as a starting point.&lt;/p&gt;
&lt;p&gt;A related thought: shouldn't the default always be shown, even if it isn't a required option? Maybe there is a good reason for this, but I don't get why non-required options hide their default in the help summary.&lt;/p&gt;
&lt;p&gt;Thanks for your work!&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12069/tools-cli-display-default-value-for-no-foo-flags-help-summary?show=12069#q12069</guid>
<pubDate>Fri, 06 Mar 2026 01:04:34 +0000</pubDate>
</item>
<item>
<title>Closed: Compile parser ahead of time</title>
<link>https://ask.clojure.org/index.php/12697/compile-parser-ahead-of-time?show=12697#q12697</link>
<description>&lt;p&gt;&lt;code&gt;tools.cli/parse-opts&lt;/code&gt; accepts the args, the option-spec, and the additional options. It calls &lt;code&gt;compile-option-specs&lt;/code&gt; and &lt;code&gt;required-arguments&lt;/code&gt; to build the &lt;code&gt;specs&lt;/code&gt; and &lt;code&gt;req&lt;/code&gt;. Then it performs the validation with those specs and req on the provided &lt;code&gt;args&lt;/code&gt; (along with the options). For a given application, the first two steps aren't going to change across calls.&lt;/p&gt;
&lt;p&gt;I propose a new &lt;code&gt;make-parse-opts-fn&lt;/code&gt; function that performs the &lt;code&gt;compile-option-specs&lt;/code&gt; and &lt;code&gt;required-arguments&lt;/code&gt; up front and returns a function that relies on the compiled &lt;code&gt;specs&lt;/code&gt; and &lt;code&gt;req&lt;/code&gt;. It could be used like this: &lt;code&gt;(def compiled-parser (make-parse-opts-fn cli-options))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Microbenchmarking with criterium shows a more than double increase in speed (tools.cli/parse-opts first, pre-compiled parser second):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; user=&amp;gt; (def cli-options
  [[&quot;-h&quot; &quot;--help&quot; &quot;This message&quot;]
   [nil &quot;--extra&quot; &quot;Output in extra format&quot;
    :default false]
   [&quot;-q&quot; &quot;--quiet&quot; &quot;Print no suggestions, only return exit code&quot;
    :default false]])
#'user/cli-options

; user=&amp;gt; (bench (cli/parse-opts [&quot;--quiet&quot; &quot;src&quot;] cli-options :in-order true))
Evaluation count : 10962 in 6 samples of 1827 calls.
             Execution time mean : 65.021329 µs
    Execution time std-deviation : 5.276033 µs
   Execution time lower quantile : 58.658638 µs ( 2.5%)
   Execution time upper quantile : 69.724228 µs (97.5%)
                   Overhead used : 9.607933 ns
nil

; user=&amp;gt; (bench (compiled-parser [&quot;--quiet&quot; &quot;src&quot;] :in-order true))
Evaluation count : 24660 in 6 samples of 4110 calls.
             Execution time mean : 25.090846 µs
    Execution time std-deviation : 253.361821 ns
   Execution time lower quantile : 24.769079 µs ( 2.5%)
   Execution time upper quantile : 25.413286 µs (97.5%)
                   Overhead used : 9.607933 ns
nil
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the additional options are lifted into the &lt;code&gt;make-parse-opts-fn&lt;/code&gt; as well (trading flexibility for speed), the difference is even more dramatic, providing roughly 10x speed increase over the existing &lt;code&gt;tools.cli/parse-opts&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; user=&amp;gt; (bench (compiled-parser-2 [&quot;--quiet&quot; &quot;src&quot;]))
Evaluation count : 73116 in 6 samples of 12186 calls.
             Execution time mean : 8.349923 µs
    Execution time std-deviation : 51.419864 ns
   Execution time lower quantile : 8.282266 µs ( 2.5%)
   Execution time upper quantile : 8.407998 µs (97.5%)
                   Overhead used : 9.607933 ns

Found 2 outliers in 6 samples (33.3333 %)
	low-severe	 1 (16.6667 %)
	low-mild	 1 (16.6667 %)
 Variance from outliers : 13.8889 % Variance is moderately inflated by outliers
nil
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can provide a patch for this if there's interest.&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12697/compile-parser-ahead-of-time?show=12697#q12697</guid>
<pubDate>Fri, 06 Mar 2026 01:03:57 +0000</pubDate>
</item>
<item>
<title>Closed: Providing nil for long option in tools.cli does not seem to work per readme</title>
<link>https://ask.clojure.org/index.php/14260/providing-nil-for-long-option-tools-cli-does-seem-work-readme?show=14260#q14260</link>
<description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;A very simplified tools.cli call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(let [cli-opts [[&quot;-m&quot; &quot;--mode MODE&quot; &quot;Application mode&quot;]]]
  (cli/parse-opts [&quot;-m&quot; &quot;hub&quot;] cli-opts)) 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Evaluates as expected to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{:options {:mode &quot;hub&quot;} ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, when I try to replace the long option with nil per the docs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(let [cli-opts [[&quot;-m&quot; nil &quot;Application mode&quot; :id :mode]]]
  (cli/parse-opts [&quot;-m&quot; &quot;hub&quot;] cli-opts))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{:options {:mode true} :arguments [&quot;hub&quot;] ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I get the same behaviour with long option = &quot;&quot;, &quot;--mode&quot;, and &quot;MODE&quot;; the only way it seems to work is with the full &quot;--mode MODE&quot;. Setting the short option to nil works as I'd expect.&lt;/p&gt;
&lt;p&gt;Tested in Clojure 1.12.0, tools.cli 1.1.230, Java 23; same behaviour on Windows 11 and MacOS 15.&lt;/p&gt;
&lt;p&gt;Am I doing something wrong, or is tools.cli? :)&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14260/providing-nil-for-long-option-tools-cli-does-seem-work-readme?show=14260#q14260</guid>
<pubDate>Fri, 06 Mar 2026 01:01:11 +0000</pubDate>
</item>
<item>
<title>Closed: Incorrect docstring for parse-opts</title>
<link>https://ask.clojure.org/index.php/14275/incorrect-docstring-for-parse-opts?show=14275#q14275</link>
<description>&lt;p&gt;In the docstring for &lt;code&gt;clojure.tools.cli/parse-opts&lt;/code&gt; (seen &lt;a rel=&quot;nofollow&quot; href=&quot;https://clojure.github.io/tools.cli/#clojure.tools.cli/parse-opts&quot;&gt;here&lt;/a&gt;), it says,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:id           The key for this option in the resulting option map. This
              is normally set to the keywordized name of the long option
              without the leading dashes.

              Multiple option entries can share the same :id in order to
              transform a value in different ways, but only one of these
              option entries may contain a :default(-fn) entry.

              This option is mandatory.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final line says &quot;This option is mandatory.&quot; which is technically true for parse-opts' internals, but it's not true for users because (as the first paragraph says) &lt;code&gt;:id&lt;/code&gt; is also generated by keywordizing the long option.&lt;/p&gt;
&lt;p&gt;May I recommend changing it to be more explicit? Something like &quot;If a long option is not provided, this option is mandatory.&quot;&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14275/incorrect-docstring-for-parse-opts?show=14275#q14275</guid>
<pubDate>Fri, 06 Mar 2026 01:00:43 +0000</pubDate>
</item>
<item>
<title>Answer selected: Dependency between options in Clojure/tools.cli ?</title>
<link>https://ask.clojure.org/index.php/14556/dependency-between-options-in-clojure-tools-cli?show=14557#a14557</link>
<description>&lt;p&gt;Here's one way to do it, but it requires for the &lt;code&gt;-f&lt;/code&gt; and &lt;code&gt;-d&lt;/code&gt; options to be specified on the command line before the &lt;code&gt;-a&lt;/code&gt; option:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(let [opts [[&quot;-a&quot; nil &quot;something&quot;
             :id :a
             :assoc-fn (fn [opts opt-id val]
                         (assoc opts opt-id
                                     (if (and (:file opts) (:dir opts))
                                       val
                                       ::missing-required)))
             :validate [#(not= % ::missing-required)
                        &quot;Missing required -f and -d options&quot;]
             :post-validation true]
            [&quot;-f&quot; &quot;--file FILE&quot; &quot;file doc&quot;]
            [&quot;-d&quot; &quot;--dir DIR&quot; &quot;dir doc&quot;]]]
  [(cli/parse-opts [&quot;-a&quot;] opts)
   (cli/parse-opts [&quot;-f x&quot; &quot;-d y&quot; &quot;-a&quot;] opts)])
=&amp;gt;
[{:options {},
  :arguments [],
  :summary &quot;  -a               something\n  -f, --file FILE  file doc\n  -d, --dir DIR    dir doc&quot;,
  :errors [&quot;Failed to validate \&quot;-a \&quot;: Missing required -f and -d options&quot;]}
 {:options {:file &quot; x&quot;, :dir &quot; y&quot;, :a true},
  :arguments [],
  :summary &quot;  -a               something\n  -f, --file FILE  file doc\n  -d, --dir DIR    dir doc&quot;,
  :errors nil}]
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14556/dependency-between-options-in-clojure-tools-cli?show=14557#a14557</guid>
<pubDate>Tue, 27 May 2025 17:37:23 +0000</pubDate>
</item>
<item>
<title>Answered: tools.cli: Support default value for arg with value</title>
<link>https://ask.clojure.org/index.php/14524/tools-cli-support-default-value-for-arg-with-value?show=14525#a14525</link>
<description>&lt;p&gt;The closest you can get is this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clojure.tools.cli=&amp;gt; (parse-opts [&quot;--diff=&quot;] [[nil &quot;--diff NAME&quot; &quot;Diff&quot; :parse-fn #(or (not-empty %) &quot;foo&quot;)]])
{:options {:diff &quot;foo&quot;}, :arguments [], :summary &quot;      --diff NAME  Diff&quot;, :errors nil}
clojure.tools.cli=&amp;gt; (parse-opts [&quot;--diff=bar&quot;] [[nil &quot;--diff NAME&quot; &quot;Diff&quot; :parse-fn #(or (not-empty %) &quot;foo&quot;)]])
{:options {:diff &quot;bar&quot;}, :arguments [], :summary &quot;      --diff NAME  Diff&quot;, :errors nil}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;clojure.tools.cli=&amp;gt; &lt;/p&gt;
&lt;p&gt;As discussed on Slack, there are reasonable cases for a value-bearing option to want to accept a string that starts with &lt;code&gt;--&lt;/code&gt; or just &lt;code&gt;-&lt;/code&gt; (consider &lt;code&gt;=&lt;/code&gt; to be optional here):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;meta-command --option-to-use=--cabbage... \
--divider=--sep-- \
--value=-1
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14524/tools-cli-support-default-value-for-arg-with-value?show=14525#a14525</guid>
<pubDate>Mon, 28 Apr 2025 19:08:37 +0000</pubDate>
</item>
<item>
<title>Commented: Can't know if value in option map is default or user-supplied</title>
<link>https://ask.clojure.org/index.php/13555/cant-know-if-value-in-option-map-is-default-or-user-supplied?show=13570#c13570</link>
<description>I read that, but I find it quite dense. Compare that paragraph to the multiple examples demonstrating individual parts of the specs above it in the readme.&lt;br /&gt;
&lt;br /&gt;
I’ll take a crack at something a little more readable.</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/13555/cant-know-if-value-in-option-map-is-default-or-user-supplied?show=13570#c13570</guid>
<pubDate>Sat, 16 Dec 2023 12:45:52 +0000</pubDate>
</item>
<item>
<title>Answered: Is it possible to parse positional arguments in tools.cli?</title>
<link>https://ask.clojure.org/index.php/9217/is-it-possible-to-parse-positional-arguments-in-tools-cli?show=9220#a9220</link>
<description>&lt;p&gt;As the maintainer of tools.cli, I'm going to give this some thought and decide whether to create a JIRA issue for it.&lt;/p&gt;
&lt;p&gt;Most programs that use tools.cli end up needing some boilerplate code for help/usage, as well as some additional parsing and/or validation of arguments so enhancing the library to make this easier would help &quot;everyone&quot; if it can be done in a fairly simple way.&lt;/p&gt;
&lt;p&gt;One conceptual issue to figure out is that the format for specifying options is only for actual options (i.e., starting with &lt;code&gt;-&lt;/code&gt; or &lt;code&gt;--&lt;/code&gt;) so there's currently nowhere to &quot;hang&quot; any free text argument processing right now.&lt;/p&gt;
</description>
<category>tools.cli</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/9217/is-it-possible-to-parse-positional-arguments-in-tools-cli?show=9220#a9220</guid>
<pubDate>Tue, 07 Apr 2020 17:23:10 +0000</pubDate>
</item>
</channel>
</rss>