zet

Stateful command tree monolith design pattern

I not-so-recently coined the term stateful command tree when seeking to describe what is very rapidly becoming the defacto standard in good command line interface design. Bonzai is the result of way too much thinking about this stuff. And now I see the same design pattern everywhere: git, kubectl, ip, netconf, and more.

But just having a command tree isn’t enough because you want to use those same commands again. Without state you end up editing a previous line rather than writing a new one. People do this all the time with kubectl --namespace blah .... For every annoying getopt dash you add, you lose simplicity. Having a way to set certain parts so that they remain valid for every subsequent command is the solution kubectl config set-context --current --namespace blah. But what if this were the rule instead of the exception.

Stateful command trees address this very problem at the root by building in an automatic, standard way to cache state in the form of vars and conf. Vars are saved to ~/.local/cache while conf is saved to ~/.config/foo. Defaults for a given application are stored in the config and overrides in the cache. The config files can therefore be preserved in dotfiles repos and such. The config is in YAML and is edited by hand rather than written out with any automation to emphasize the nature and difference between conf and vars.

What makes Bonzai so amazing is that a person can compose dozens of stateful command trees from anywhere with a simple import statement and yet all of them will change the same conf and vars. There is separation in the form of pathing that matches the location of the branch as grafted into the overall monolith tree. But applications are free to inspect and modify other values as well allowing monolith creators ultimate freedom and flexibility when combining together any combination of stateful command trees. This provides a level of clear configuration management unparalleled by any other commander library.