SKILL.md

  1---
  2name: jq
  3description: Use when the user needs to query, filter, reshape, extract, create, construct, count, sum, or aggregate JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations, or when answering "how many", "how much", "which", or "what are the" questions over JSON or arrays.
  4---
  5
  6# jq — Built-in JSON Processor
  7
  8Crush ships a built-in `jq` command (via `github.com/itchyny/gojq`) available
  9in the bash tool. No external binary is required.
 10
 11## Supported Flags
 12
 13| Flag | Description |
 14|------|-------------|
 15| `-r`, `--raw-output` | Output strings without quotes |
 16| `-j`, `--join-output` | Like `-r` but no trailing newline |
 17| `-c`, `--compact-output` | One-line JSON output |
 18| `-s`, `--slurp` | Read all inputs into an array |
 19| `-n`, `--null-input` | Use `null` as input (ignore stdin) |
 20| `-e`, `--exit-status` | Exit 1 if last output is `false` or `null` |
 21| `-R`, `--raw-input` | Read each line as a string, not JSON |
 22| `--arg name value` | Bind `$name` to a string value |
 23| `--argjson name value` | Bind `$name` to a parsed JSON value |
 24
 25File arguments after the filter are also supported: `jq '.foo' file.json`.
 26
 27## Differences from Standard jq
 28
 29The built-in uses gojq, which is a pure-Go jq implementation. Key
 30differences:
 31
 32- **No object key ordering** — keys are sorted by default; `keys_unsorted`
 33  and `-S` are unavailable.
 34- **Arbitrary-precision integers** — large integers keep full precision
 35  (addition, subtraction, multiplication, modulo, division when divisible).
 36- **String indexing** — `"abcde"[2]` returns `"c"`.
 37- **Not supported** — `--ascii-output`, `--seq`, `--stream`,
 38  `--stream-errors`, `-f`/`--from-file`, `--slurpfile`, `--rawfile`,
 39  `--args`, `--jsonargs`, `input_line_number`, `$__loc__`, some regex
 40  features (backreferences, look-around).
 41- **YAML** — gojq supports `--yaml-input`/`--yaml-output` but the
 42  built-in does not currently expose these flags.
 43
 44## Common Patterns
 45
 46Extract a field:
 47```sh
 48echo '{"name":"crush"}' | jq '.name'
 49```
 50
 51Filter an array:
 52```sh
 53echo '[1,2,3,4,5]' | jq '[.[] | select(. > 3)]'
 54```
 55
 56Reshape objects:
 57```sh
 58echo '{"first":"Ada","last":"Lovelace"}' | jq '{full: (.first + " " + .last)}'
 59```
 60
 61Use variables:
 62```sh
 63echo '{}' | jq --arg host localhost --argjson port 8080 '{host: $host, port: $port}'
 64```
 65
 66Slurp multiple JSON values:
 67```sh
 68echo '{"a":1}{"b":2}' | jq -s '.'
 69```
 70
 71Compact output for piping:
 72```sh
 73echo '{"a":1}' | jq -c '.a += 1'
 74```
 75
 76Raw string output:
 77```sh
 78echo '["one","two","three"]' | jq -r '.[]'
 79```
 80
 81Process a file:
 82```sh
 83jq '.dependencies | keys' package.json
 84```
 85
 86Null input for constructing JSON:
 87```sh
 88jq -n --arg msg hello '{"message": $msg}'
 89```
 90
 91## Tips
 92
 93- Pipe jq output to other commands: `jq -r '.url' data.json | xargs curl`
 94- Chain filters with `|` inside the expression, not shell pipes.
 95- Use `try` to suppress errors on missing keys: `jq 'try .foo.bar'`
 96- Use `// "default"` for fallback values: `jq '.name // "unknown"'`
 97- Use `@csv`, `@tsv`, `@base64`, `@html`, `@uri` for format strings.
 98
 99## Filtering remote JSON with `fetch`
100
101The `fetch` tool accepts an optional `jq` parameter that applies a jq
102expression to the response body server-side. Prefer it over pulling entire
103JSON payloads into context — it's faster, cheaper, and avoids manual
104counting mistakes.
105
106```text
107fetch(url="https://api.example.com/items", jq="length")
108fetch(url="https://api.example.com/items", jq="[.[].name]")
109fetch(url="https://catwalk.charm.sh/v2/providers",
110      jq="[.[].models | length] | add")
111```
112
113When `jq` is set, `format` is ignored (and optional) and the body is
114parsed as JSON.
115
116### Fixing jq filter errors
117
118If your jq filter assumes the wrong top-level shape, `fetch` returns an
119error with an `(input shape: ...)` hint. **Fix the filter using that
120hint** — do not retry without a filter. Common corrections:
121
122| Hint | Your filter | Fixed filter |
123|---|---|---|
124| `array of N items; first item is object with keys: ...` | `.providers[].name` | `.[].name` |
125| `object with keys: data, meta, ...` | `.[].name` | `.data[].name` |
126| `object with keys: items, ...` | `length` | `.items \| length` |
127
128### Large JSON without a filter
129
130If `fetch` ends its response with a `[crush-hint: response body is N bytes
131of JSON. Prefer re-calling fetch() with a jq expression ...]` banner,
132re-issue the call with a `jq` expression. Loading multi-hundred-KB JSON
133payloads into context tends to trigger context-overflow errors on
134downstream providers. The banner is appended (not prepended), so the
135JSON body above it is still valid and parseable on its own.