HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
c-blake
cligen
Nim2018–2026
c-blake / cligen

cligen

Nim library to infer/generate command-line-interfaces / option / argument parsing; Docs at

8Distinct people
57Mentions
0Explicit recommenders
584GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Nim library to infer/generate command-line-interfaces / option / argument parsing; Docs at

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:03:16 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year57 dated mentions

Observed mentions: 2018-08-17 23:26:38 UTC to 2026-10-13 15:14:01 UTC.

0369122018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20182019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 10 mentions; 0 submissions, 10 comments20222023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 12 mentions; 0 submissions, 12 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 10 mentions; 1 submissions, 9 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC101
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC101
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC808
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC808
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC10010
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC12012
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC505
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC1019
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC202

What Hacker News says

57 sources
Most things like "sanely" and "20%" are pretty subjective. To me writing (or really reading well written) Nim (https://nim-lang.org) is less effort than writing Python or Typescript. Nim is mostly Ada & Lisp ideas packaged in a more terse & flexible surface syntax. Nim also has nice compile-time introspection and very low effort macros to allow packaging near zero-code APIs like github.com/c-blake/cligen. Also, something like 5 out of 5 times I've investigated some Rust alternative to some Nim code, the Rust ran more slowly than my Nim on my tested CPUs. With access to inline asm, all speed is ultimately more a measure of effort applied than PLang. So those perf ideas are just "with my level of effort". Even Python via Cython has pretty direct access to asm. The "do it in pure X" that Sun popularized (even in a meta-/cross-PLang-se
Read the rest
nse) as a business attempt to define Java virtual machines as The platform has had many casualties, not the least of which is the quality of discussion of PLang practicalities, not just on HN, but everywhere.
In 11 year old unsoundness bugs found in Rust borrow checker
Actually echo is not a statement - Nim's syntax is just much more flexible than Python so what looks like a statement in Python is actually just a UFCS/Command-Line "call" (of macro/template/generic/procedure aka "routine"). It is super easy to roll your own print function [1] and there is no penalty for doing so except that the std lib does not provide a "common parlance". So, that wheel might get reinvented a lot. A lot of things like this in cligen because it is a leaf dependency (the literally 1..3 identifier CLI "api") and so many "drive by" PLang tester-outers might want to roll a little CLI around some procs their working on. Also, beyond the echo x,y is same as echo(x,y) or x.echo(y) or x.echo y, the amount of syntax flexibility is dramatically more than Python. You can have user-defined operators like `>>>` or `!!!` or `.*`.
Read the rest
There are also some experimental and probably buggy compiler features to do "term re-writing macros" so that your matrix/bignum library could in theory re-write some bz*ax+y expression into a more one-pass loop (or maybe conditionally depending upon problem scale). I sometimes summarize this as "Nim Is Choice". Some people don't like to have to/get to choose. To others it seems critical. Someone even did some library to make `def` act like `proc`, but I forget its name. Nim has a lot more routine styles than Python, including a special iterator syntax whose "call" is a for-construct. [1] https://github.com/c-blake/cligen/blob/master/cligen/print.n...
In Nim 2.2.6
I would also push back (agreeing with @TylerE, but linking in this part of the subthread seems best). It all depends, but sometimes macros change the division of labor between library authors and library users so that they specifically have to learn less. For example, https://github.com/c-blake/cligen makes it so that you don't really have to learn an "API" to roll a nice CLI on top of a procedure. You just need to learn literally 2 or maybe 3 names: "cligen", "dispatch", and maybe "help={}". Everything else, you already know from knowing Nim basics (or even Python basics). (The dispatchGen macro itself is rather a monster of static introspection and code generation and not at all pedagogical -- mostly from filling like 100 user requests on closed issues.) It's just important to keep in mind that library / framework authors, library
Read the rest
/ framework users, and final end users are not all the same person or even type of person. Metaprogramming enables the first group the most, but can deliver benefits to the latter two groups by easing their lives quite a bit. This is easy to lose track of in a niche language like Nim where all 3 groups might well be the same human for most of the life of some project. This partly also relates to how much of a "full stack debugger (of either correctness or performance or both)" personality one has. Then there are even more layers -- like all the levels in the language / compiler itself down to the CPU and beyond (such as "u-code" & micro-architectural resource sharing). What macros mostly do is enable fluid, simple syntax for things either too rare, too niche, too unanticipated or too disagreed upon to be in "the main language", whatever that is. As a shibboleth (or marker for group inclusion), the existence of this expressivity selects for programmers who want to fix rare, niche, unanticipated or disagreed upon things, and these people can be even harder "cats to herd". Nim has other very flexible features - such as the rare "user-defined operators" that enable very nice looking custom syntax. But you can also SCOPE their use very simply. E.g., put their definitions inside a template so that you can say `ptrArithmeticNow: expression` and only have pointer arithmetic within `expression` (maybe with +! to look a little diff from ordinary arithmetic), and (ptrArithmetic itself can be scoped within a module name). It also has even more powerful (and more rare) term-rewriting macros, used most commonly in Lisp systems, perhaps doing computer algebra.
In Why Nim?
The answer to your question is that command-lines have a much larger diversity of syntax (even to get help!) than most people realize. Folks have their 30..60 commands they run frequently and don't run into many or conveniently forget/neglect older ones like `gcc` or `tar` or `dd`. Many people (not saying you specifically) do not even realize that double-dash long options are a GNU extension never standardized or that Python toolkits typically allow --my-opt for --my-option abbreviations, just to name a couple of the dozen variations (space or '=', or ':' or '/' or any of the above or etc., etc.). There are probably hundreds if not thousands of syntax possibilities, but people often act like there is only one. As an example of diversity estimation that you can try at home, a couple of times I have run every single command in my command
Read the rest
search PATH with --help </dev/null >/tmp/help.$c 2>&1 . Caution - be careful if you do this! Have backups/checksums of everything important and run as an unprivileged user. I always have to kill off several processes that just hang doing something or otherwise manually intervene. Anyway, this alone suggests data collection of help text is not a trivial problem. Beyond data collection, many commands did not/do not use CLI toolkits at all. Their commands may have even less regular syntax. Freeform help makes it harder to produce a regular help syntax to convert into the interpreter needed by a completion system. That said, as elsethread commented for some toolkits the Zsh _gnu_generic works great! It essentially IS the "automagic" system you might want, just for a highly restricted circumstance. Any CLI toolkit itself does have the data, by necessity. So, if the CLI framework supports the 2 or 3 common shells there is no need for a translator exactly. You just need a code generator. There is a stab at an auto-generation framework from said data for the Nim CLI toolkit, cligen, over at: https://github.com/c-blake/cligen/blob/master/util/complgen.... but it only works for Zsh right now. Anyway, I don't think perfect should be the enemy of the good or anything like that, but you seemed to ask an earnest "why" question and these are some of the complexities.
In Writing simple tab-completions for Bash and Zsh
_gnu_generic is fantastic. I use it all the time. If your CLI toolkit emits colorized help, but skips said colorization if NO_COLOR[1] is set then you can prefix _gnu_generic with NO_COLOR=1 as in https://github.com/c-blake/cligen/wiki/Zsh-completion-for-cl... for the cligen Nim CLI toolkit. A similar thing in Bash is `complete -F _longopt YourCmd`, but these will not work with "multi-commands" that have "sub-commands" as the article of this thread covers. Truth is, as non-standard as GNU long opts already are, how subcommands work is even more non-standard (are there even global options? Or between each subcommand? Is it how Python does it? Or Go? Or some one specific library or ..?) [^1]: https://no-color.org/
In Writing simple tab-completions for Bash and Zsh
There hasn't been a ton of benchmark comparisons. From memory, on what remains in examples/: The cligen/dents stuff is faster than anything not so enabled with a new kernel call and some perf stuff mentioned right in the comments there, but Linux has moved to blocking installing syscalls from modules. I've timed gl/grls against ripgrep favorably, but it's obviously a very simple pattern subcase. Mostly those were to demo cligen/procpool. examples/cols was faster than awk or xsv for me (which has really moved to https://github.com/c-blake/bu now along with several others like `rp` - which is kind of a "concept piece" showing that any command-line is kind of a "language" already and with just a little codegen magic you can beat awk at most of its own games: https://github.com/c-blake/bu/blob/main/doc/rp.md). Some subthread in one of the h
Read the rest
undreds of closed issue threads got into a comparison of dups and jdupes ( https://github.com/c-blake/cligen/issues/99#issuecomment-485... ) where Jody shows up. I mean, in my test cases dups fared well, but on what many would call the "boring non-IO bound case". For IO bound cases things rapidly depend a lot on your host OS & devices. I should say that "the point" of most of these things was not caffeine-fueled rage optimization, but more to show how easy it is to get performance & functionality out of Nim. Almost all are much smaller programs (perhaps with many fewer features) than their competing programs. But such catering to The Unix Philosophy felt like it fit well with a CLI toolkit. { Even sys_batch is like a 30 lines of C virtual machine for inside Linux instead of untold 10s of thousands for eBPF & IO uring. While porting to other arches would be more, that 30 lines could probably stay the same. }
In Cligen: A Native API-Inferred Command-Line Interface Generator for Nim
This is an outstanding library which is more of a CLI framework. It's seriously optimized and includes ready to use modules which are alternative to Nim's standard library or more tailored/opinionated interfaces for basic POSIX software building blocks. Don't skip going over examples[1]. All of those are fully functional programs, some are pretty niche, but all are very usable and, I bet @cb321 will confirm, in some cases are competitive with widely-used alternatives. https://github.com/c-blake/cligen/tree/master/examples
In Cligen: A Native API-Inferred Command-Line Interface Generator for Nim
I got very little speed-up on pypy from being in a function (0.043 vs 0.033), but I got a 1.8X speed-up for py2 vs py3 (0.7686/.4322 = 1.78). (All programs emit 4999874750 as expected.) EDIT: This uses a Nim program https://github.com/c-blake/bu/blob/main/doc/ru.md run as `ru -t`, but for the very fast variants you can get a more precise wall time from https://github.com/c-blake/bu/blob/main/doc/tim.md pypy3_10-7.3.16_p1 - (first form,2nd form) x same in a func TM 0.045421363 wall 0.034517 usr 0.010855 sys 99.9 % 56476 mxRS minCall TM 0.043447211 wall 0.029492 usr 0.013763 sys 99.6 % 56124 mxRS ifStmt TM 0.033408064 wall 0.020605 usr 0.012758 sys 99.9 % 55960 mxRS minCallInFunc TM 0.033115636 wall 0.026059 usr 0.007018 sys 99.9 % 55956 mxRS ifStmtInFunc python-2.7.18_p16 TM 1.755861105 wall 1.751740 usr 0.
Read the rest
001991 sys 99.9 % 5944 mxRS TM 0.940162912 wall 0.935362 usr 0.003988 sys 99.9 % 5916 mxRS TM 1.155755936 wall 1.151529 usr 0.002993 sys 99.9 % 5928 mxRS TM 0.432215672 wall 0.430851 usr 0.000998 sys 99.9 % 5800 mxRS python-3.11.9_p1 TM 2.678891504 wall 2.675141 usr 0.000994 sys 99.9 % 7992 mxRS TM 1.348009364 wall 1.344612 usr 0.001995 sys 99.9 % 7864 mxRS TM 2.018986091 wall 2.014702 usr 0.001994 sys 99.9 % 7972 mxRS TM 0.768633122 wall 0.766915 usr 0.000997 sys 99.9 % 7980 mxRS I recall when Python3 was first going through its growing pains in the mid noughties that promises of eventually clawing back performance. This clawback now seems to have been a fantasy (or perhaps they have just piled on so many new features that they clawed back and then regressed?). Anyway, Nim is even faster than PyPy and uses less memory than either version of CPython: doIt.nim: proc doIt() = var i = 10000000 var r = 0 while i > 0: i = i - 1 r += min(i, 500) echo r doIt() #TM 0.024735 wall 0.024743 usr 0.000000 sys 100.0% 1.504 mxRM In terms of "how Python-like is Nim", all I did was change `def` to `proc` and add the 2 `var`s and change `print` -> `echo`. { EDIT: though if you love Py print(), there is always https://github.com/c-blake/cligen/blob/master/cligen/print.n... or some other roll-your-own idea. Then instead of py2/py3 print x,y vs print(x,y) you can actually do either one in Nim since its call syntax is so flexible. } It is perhaps noteworthy that, if the values are realized in some kind of array rather than generated by a loop, that modern CPUs can do this kind of calculation well with SIMD and compilers like gcc can even recognize the constructs and auto-vectorize. Of course, needing to load data costs memory bandwidth which may not be great compared to SIMD instruction throughput at scales past 80 MiB as in this problem.
In Recent Performance Improvements in Function Calls in CPython

Showing the 15 most recent of 57 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.