jo: Build JSON From the Shell
jo builds a JSON object from key=value arguments, handling types and nesting so you do not hand-assemble JSON with echo and risk broken quoting.
Constructing JSON payloads in bash with string concatenation is a quoting minefield. jo takes key=value pairs and emits valid JSON, escaping values for you.
What it does
jo turns its key=value arguments into a JSON object. It infers numbers and booleans, builds arrays with -a, nests via key=$(jo ...) substitution or the key[subkey]= syntax, and forces a string with a : prefix on the value.
Common usage
# simple object with inferred types
jo name=ada age=42 active=true
# array of values
jo -a 1 2 3
# nested object via substitution
jo user=$(jo name=ada id=1) ts=$(date +%s)
# force a value to stay a string
jo zip=:01234Options
| Form / flag | What it does |
|---|---|
| key=value | Add a key with an inferred type |
| -a | Produce a JSON array from the arguments |
| key=:value | Force the value to be a string |
| key=@file | Read the value from a file |
| key=%file | Base64-encode a file as the value |
| -p | Pretty-print the output |
In CI
Build a webhook or API payload safely: jo event=deploy sha="$GITHUB_SHA" ok=true | curl -d @- "$WEBHOOK". Because jo escapes values, a commit message with quotes or newlines will not corrupt the JSON the way a hand-built echo "{...}" would.
Common errors in CI
jo: command not found: apt-get install jo or brew install jo. A value like 007 or true is coerced to a number/boolean unexpectedly; prefix with : to keep it a string (code=:007). An argument missing the = triggers jo: argument ... is neither k=v nor k@v. Unquoted values containing spaces get split by the shell into separate arguments, so quote them: msg="hello world".