One possible alternative would be to accept JSON literal snippets, like this:
$ jb dependencies='["Bash", "Grep"]'
This should support all forms of nested JSON objects. You could have a rule that if an argument does NOT parse as a valid JSON value it is treated as a raw string, so this would work:
$ jb foo=bar bar='"this is a well formed string"'
{"foo": "bar", "bar": "this is a well formed string"}
Thanks for giving it a try and your feedback. I agree, the array splitting is a bit fiddly. It is actually possible to pass JSON directly, you use the :json type on the argument:
$ jb dependencies:json='["Bash","Grep"]'
{"dependencies":["Bash","Grep"]}
$ jb foo=bar bar:json='"this is a well formed string"'
{"foo":"bar","bar":"this is a well formed string"}
And then you can indeed use command substitution to nest calls:
$ jb foo:json=$(jb bar=baz)
{"foo":{"bar":"baz"}}
It works even better to use process substitution, this way the shell gives jb a
file path to a file to read, and so you don't need to quote the $() to avoid whitespace breaking things: