Claude Code Plugins

Community-maintained marketplace

Feedback

JSON processing, parsing, and manipulation. STRONGLY PREFERRED for all JSON formatting, filtering, transformations, and analysis. Use instead of Python/Node.js scripts for JSON operations.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name jq
description JSON processing, parsing, and manipulation. STRONGLY PREFERRED for all JSON formatting, filtering, transformations, and analysis. Use instead of Python/Node.js scripts for JSON operations.

jq - JSON Processing

IMPORTANT: jq is the STRONGLY PREFERRED tool for ALL JSON formatting, parsing, manipulation, and analysis tasks. Use jq instead of Python/Node.js scripts, grep, awk, or other text processing tools when working with JSON data.

Core Philosophy

  • Always use jq for JSON: If the data is JSON or can be converted to JSON, use jq
  • Streaming-friendly: jq processes JSON as a stream, making it memory-efficient for large files
  • Composable: jq filters can be chained with pipes, just like shell commands
  • Pure and functional: jq transformations are predictable and side-effect-free

Basic Usage Patterns

Pretty-Printing and Formatting

# Pretty-print JSON (most common use case)
cat file.json | jq '.'
jq '.' file.json

# Compact output (remove whitespace)
jq -c '.' file.json

# Sort keys alphabetically
jq -S '.' file.json

# Raw output (no quotes for strings)
jq -r '.field' file.json

# Null input (construct JSON from scratch)
jq -n '{name: "value", count: 42}'

Selecting and Filtering

# Select a single field
jq '.field' file.json

# Select nested field
jq '.user.email' file.json

# Select array element by index
jq '.[0]' array.json
jq '.[2:5]' array.json  # Array slice

# Select multiple fields (create new object)
jq '{name: .name, email: .email}' file.json

# Filter array elements
jq '.[] | select(.age > 21)' users.json

# Filter with multiple conditions
jq '.[] | select(.active == true and .role == "admin")' users.json

# Filter and select fields
jq '.[] | select(.price < 100) | {name, price}' products.json

Array Operations

# Map over array (transform each element)
jq 'map(.name)' users.json
jq '[.[] | .email]' users.json  # Alternative syntax

# Filter then map
jq 'map(select(.active)) | map(.name)' users.json

# Get array length
jq 'length' array.json
jq '.items | length' file.json

# Sort array
jq 'sort' numbers.json
jq 'sort_by(.created_at)' items.json

# Reverse array
jq 'reverse' array.json

# Unique values
jq 'unique' array.json
jq 'unique_by(.category)' items.json

# Group by field
jq 'group_by(.category)' items.json

# Flatten nested arrays
jq 'flatten' nested.json
jq 'flatten(2)' deeply_nested.json  # Flatten 2 levels

Aggregations and Statistics

# Sum values
jq 'map(.price) | add' items.json
jq '[.[] | .count] | add' data.json

# Average
jq 'map(.score) | add / length' scores.json

# Min/max
jq 'map(.price) | min' products.json
jq 'map(.price) | max' products.json
jq 'min_by(.created_at)' items.json
jq 'max_by(.score)' results.json

# Count occurrences
jq 'group_by(.status) | map({status: .[0].status, count: length})' items.json

Transforming Data

# Add field
jq '. + {new_field: "value"}' file.json

# Update field
jq '.price = .price * 1.1' product.json
jq '.updated_at = now' record.json

# Rename field
jq '{name: .old_name, other: .other}' file.json

# Delete field
jq 'del(.sensitive_data)' file.json

# Conditional updates
jq 'if .price > 100 then .category = "premium" else . end' product.json

# Map with transformation
jq 'map(. + {full_name: "\(.first_name) \(.last_name)"})' users.json

Combining and Merging

# Merge objects
jq '. + {extra: "data"}' file.json
jq '. * {override: "value"}' file.json  # Recursive merge

# Combine arrays
jq '. + [1,2,3]' array.json

# Merge multiple files
jq -s '.[0] + .[1]' file1.json file2.json

# Slurp mode (combine into array)
jq -s '.' file1.json file2.json file3.json
jq -s 'map(.items) | flatten' *.json

Working with Keys

# Get all keys
jq 'keys' object.json
jq 'keys_unsorted' object.json

# Check if key exists
jq 'has("field")' file.json

# Get values
jq 'values' object.json
jq '.[] | values' array.json  # Filter out nulls

# Convert object to array of key-value pairs
jq 'to_entries' object.json
jq 'to_entries | map({key: .key, value: .value})' object.json

# Convert array of pairs back to object
jq 'from_entries' pairs.json

String Operations

# String interpolation
jq '"\(.first_name) \(.last_name)"' user.json

# String functions
jq '.name | ascii_downcase' file.json
jq '.email | ascii_upcase' file.json
jq '.text | ltrimstr("prefix:")' file.json
jq '.url | rtrimstr(".html")' file.json

# Split and join
jq '.tags | split(",")' file.json
jq '.words | join(" ")' file.json

# Regular expressions
jq '.email | test("@example\\.com$")' user.json
jq '.text | match("\\b\\w+@\\w+\\.\\w+\\b")' content.json
jq '.name | sub("old"; "new")' file.json
jq '.text | gsub("\\s+"; " ")' file.json  # Replace all

Conditional Logic

# Simple if-then-else
jq 'if .age >= 18 then "adult" else "minor" end' user.json

# Multiple conditions
jq 'if .score > 90 then "A" elif .score > 80 then "B" else "C" end' result.json

# Alternative operator (handle null/false)
jq '.optional_field // "default"' file.json

# Try-catch (handle errors gracefully)
jq 'try .field.nested catch "not found"' file.json

Type Conversions

# Convert to string
jq 'tostring' number.json

# Convert to number
jq 'tonumber' string.json

# Type checking
jq 'type' value.json
jq '.[] | select(type == "number")' mixed.json

# Array/object detection
jq 'if type == "array" then length else 1 end' value.json

Output Formatting

# Tab-separated values
jq -r '.[] | [.name, .email, .age] | @tsv' users.json

# CSV output
jq -r '.[] | [.name, .email, .age] | @csv' users.json

# URL encoding
jq -r '@uri' string.json

# Base64 encoding/decoding
jq -r '@base64' string.json
jq -r '@base64d' encoded.json

# HTML encoding
jq -r '@html' string.json

# Shell escaping
jq -r '@sh' command.json

Advanced Patterns

# Recursive descent (search all levels)
jq '.. | .id? | select(. != null)' nested.json

# Walk (apply transformation recursively)
jq 'walk(if type == "string" then ascii_downcase else . end)' file.json

# Path queries
jq 'path(.items[].name)' file.json
jq 'getpath(["items", 0, "name"])' file.json

# Limit output
jq 'limit(5; .[] | select(.active))' items.json

# Until condition
jq 'until(. > 100; . * 2)' number.json

# Reduce (fold)
jq 'reduce .[] as $item (0; . + $item.count)' items.json
jq 'reduce .[] as $item ({}; . + {($item.key): $item.value})' pairs.json

Working with API Responses

# Pretty-print API response
curl -s api.example.com/data | jq '.'

# Extract specific fields from API
curl -s api.example.com/users | jq '.[] | {id, name, email}'

# Filter and transform
curl -s api.example.com/items | jq 'map(select(.active)) | sort_by(.created_at) | reverse | .[0:10]'

# Pagination handling
for page in {1..5}; do
  curl -s "api.example.com/items?page=$page" | jq '.items[]'
done | jq -s '.'

# Error handling
curl -s api.example.com/data | jq 'if .error then .error.message else .data end'

Log Analysis

# Parse JSON logs
cat app.log | jq -R 'fromjson? | select(.level == "error")'

# Group errors by type
cat app.log | jq -R 'fromjson? | select(.level == "error")' | jq -s 'group_by(.error_type) | map({type: .[0].error_type, count: length})'

# Time-based filtering
cat app.log | jq -R 'fromjson? | select(.timestamp > "2024-01-01")'

# Extract stack traces
cat app.log | jq -R 'fromjson? | select(.stack_trace) | .stack_trace'

Multi-File Processing

# Merge multiple JSON files
jq -s 'add' file1.json file2.json file3.json

# Process each file separately, collect results
jq -s 'map(.)' *.json

# Cross-file analysis
jq -s 'map(.items) | flatten | group_by(.category)' *.json

# Join files (like SQL join)
jq -s '.[0].users as $users | .[1].orders | map(. + {user: ($users[] | select(.id == .user_id))})' users.json orders.json

Performance Optimization

# Streaming mode for large files (don't load entire file)
jq --stream 'select(length == 2)' huge.json

# Process line-by-line for NDJSON (newline-delimited JSON)
cat data.ndjson | jq -c '.'

# Use compact output to reduce size
jq -c '.' file.json > compressed.json

# Limit memory by processing incrementally
cat stream.json | jq -c 'select(.important)' >> filtered.json

Debugging

# Debug mode (show intermediate values)
jq --debug '.field' file.json

# Print to stderr while continuing
jq 'debug | .field' file.json

# Add debugging output
jq '. as $orig | .field | debug | $orig' file.json

# Validate JSON
jq empty file.json  # No output = valid JSON

# Check for null fields
jq 'paths(. == null)' file.json

Common Patterns for Claude Code Tasks

Extract Configuration Values

# Get specific config value
jq -r '.database.host' config.json

# Get all environment variables
jq -r '.env | to_entries | .[] | "\(.key)=\(.value)"' config.json

Process API Responses

# Extract IDs from response
gh api /repos/owner/repo/issues | jq '.[].number'

# Format for display
gh api /repos/owner/repo/pulls | jq -r '.[] | "\(.number): \(.title)"'

Transform Test Results

# Parse test output
cat test-results.json | jq '{total: .stats.tests, passed: .stats.passes, failed: .stats.failures}'

# Find failed tests
cat test-results.json | jq '.tests[] | select(.state == "failed") | .title'

Modify Package Files

# Update package.json version
jq '.version = "2.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json

# Add dependency
jq '.dependencies["new-package"] = "^1.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json

# Remove dev dependency
jq 'del(.devDependencies["old-package"])' package.json > package.json.tmp && mv package.json.tmp package.json

When NOT to Use jq

  • Binary data: jq is for text-based JSON only
  • Very simple extraction: For trivial field access where grep would suffice
  • Modifying files in place: jq doesn't support in-place editing (use temp files)
  • Non-JSON data: Use appropriate tools (xsv for CSV, yq for YAML, etc.)

Error Messages and Troubleshooting

Common Errors

# "parse error: Invalid numeric literal"
# → JSON has invalid syntax, validate with: jq empty file.json

# "jq: error: Cannot index string with string"
# → Trying to access field on non-object, check types first

# "jq: error: null cannot be parsed as JSON"
# → Input is null or empty, use: jq -R 'fromjson?'

# "Cannot iterate over null"
# → Field doesn't exist, use: jq '.field // []'

Validation

# Validate JSON syntax
jq empty file.json && echo "Valid JSON" || echo "Invalid JSON"

# Pretty-print to find errors
jq '.' file.json

Performance Considerations

  1. Use -c for compact output when piping to other commands
  2. Stream large files with --stream or process line-by-line for NDJSON
  3. Filter early to reduce data size before complex transformations
  4. Avoid unnecessary array creation - use streaming operations when possible
  5. Use built-in functions like map, select, group_by instead of manual loops

Integration with Other Tools

# With curl
curl -s api.example.com/data | jq '.results[]'

# With grep (for NDJSON)
cat logs.ndjson | grep "error" | jq '.'

# With awk
cat data.json | jq -r '.[] | @tsv' | awk -F'\t' '{print $1, $3}'

# With xargs
jq -r '.files[]' list.json | xargs -I {} cp {} dest/

# With parallel processing
cat items.json | jq -c '.[]' | parallel -j4 'echo {} | jq ".id"'

Resources