Preview — landing now, not final. kaish (会sh) is a
predictable shell for AI agents. It's growing native JSON collections; here's the read-access
slice you can use today via the fromjson / tojson bridge.
u=$(fromjson '{"name":"amy","role":"maintainer"}')
echo ${u[name]} is the ${u[role]} # amy is the maintainer
echo "record has ${#u} keys" # record has 2 keys
k=name; echo ${u[$k]} # amy ($var is a dynamic key)
xs=$(fromjson '["apple","banana","cherry"]')
echo "${xs[0]} .. ${xs[-1]}" # apple .. cherry (negative index)
echo ${xs[0:2]} # ["apple","banana"] (end-exclusive slice → a list)A subscript that lands on a JSON scalar unwraps to a real value — so comparisons and arithmetic are typed, no coercion:
s=$(fromjson '{"web":{"port":8080,"healthy":false}}')
echo $(( ${s[web][port]} + 1 )) # 8081 (real integer math)
[[ ${s[web][healthy]} == false ]] && echo "web is down" # typed bool → "web is down"
for svc in $(fromjson '[{"name":"web","port":8080},{"name":"api","port":9000}]'); do
echo "${svc[name]} -> ${svc[port]}"
done
# web -> 8080
# api -> 9000
tojson $s # serialize back out; fromjson "$(tojson $x)" round-trips $xThe design rule is crash > corrupt: a bad access never returns a plausible wrong answer — it errors, and the error teaches the fix.
${u.name} → kaish uses bracket access, not dots — write the key as: [name]
${u[nope]} → no such key
${xs[9]} → index out of bounds (list length 2)
${xs[web]} → string key on a list — use an integer index
${u[0]} → integer index on a record — record keys are strings, use ${u["0"]}
[[ $xs == banana ]] → cannot compare a list to a string — test membership with `[[ x in $coll ]]`
fromjson/tojsonare the JSON ingress/egress bridge; everything in between is a structured value, not text.- Brackets only — no dots. Barewords are literal keys,
$varis dynamic, integers index lists. Scalars unwrap at the access boundary so==and$(( ))are typed. - jq is still right there for transforms and existence checks
(
echo $u | jq 'has("tls")') — external JSON stays external, never silently re-typed.
Still to come in this line of work: list/record literals (xs=[a b c]), push, native
[[ k in $r ]] membership, and record iteration by keys.