gron Session 03: Composition
The three tools together. gron discovers structure, jq extracts and reshapes, yq bridges YAML. This session builds real multi-tool pipelines.
Pre-Session State
-
Can use gron for structure discovery
-
Can extract data with jq
-
Can read YAML with yq
Lesson 1: The Discovery-to-Extraction Pattern
Pattern: gron → grep → note the path → jq extracts.
Exercise 1.1: Full workflow
# Step 1: What does this API return?
gh api 'repos/EvanusModestus/domus-captures' | gron | grep -i topic
# Step 2: Found json.topics — extract with jq
gh api 'repos/EvanusModestus/domus-captures' | jq '.topics'
Exercise 1.2: Multi-hop discovery
# Commits have nested structure — where is the date?
gh api 'repos/EvanusModestus/domus-captures/commits?per_page=1' | gron | grep date
# Found: json[0].commit.author.date AND json[0].commit.committer.date
# Extract the one you want:
gh api 'repos/EvanusModestus/domus-captures/commits?per_page=5' | jq '.[].commit.author.date'
Lesson 2: YAML → JSON → gron
Pattern: yq converts YAML to JSON, gron explores it, jq extracts.
Exercise 2.1: Explore antora.yml structure
yq -o=json '.' ~/atelier/_bibliotheca/domus-captures/docs/asciidoc/antora.yml | gron | head -30
Exercise 2.2: Find all IP-like values
yq -o=json '.' ~/atelier/_bibliotheca/domus-captures/docs/asciidoc/antora.yml | gron | grep -E '[0-9]+\.[0-9]+\.[0-9]+'
Exercise 2.3: Extract discovered paths with jq
# gron showed: json.asciidoc.attributes["ad-dc-ip"] = "10.50.1.50";
yq -o=json '.asciidoc.attributes' ~/atelier/_bibliotheca/domus-captures/docs/asciidoc/antora.yml |
jq 'to_entries[] | select(.value | tostring | test("10\\.50")) | "\(.key) = \(.value)"' -r
Lesson 3: Cross-Repo Exploration
Exercise 3.1: Compare repo structures
# Field-level diff between two repos
diff <(gh api 'repos/EvanusModestus/domus-captures' | gron | awk -F= '{print $1}' | sort) \
<(gh api 'repos/EvanusModestus/domus-nvim' | gron | awk -F= '{print $1}' | sort) | head -20
Exercise 3.2: Cross-repo commit activity
for repo in domus-captures domus-nvim domus-infra-ops; do
gh api "repos/EvanusModestus/$repo/commits?per_page=3" |
jq --arg repo "$repo" '.[].commit | {repo: $repo, date: .author.date, msg: .message | split("\n")[0]}'
done | jq -s 'sort_by(.date) | reverse | .[:10]'
Lesson 4: gron for Debugging
Exercise 4.1: Find null values
cat << 'EOF' | gron | grep null
{"users": [{"name": "alice", "email": "alice@example.com"}, {"name": "bob", "email": null}]}
EOF
Instantly shows which fields are null. In large API responses, this is faster than scanning JSON.
Exercise 4.2: Find empty arrays
cat << 'EOF' | gron | grep '\[\]'
{"data": {"results": [], "errors": [], "warnings": ["low disk"]}}
EOF
Exercise 4.3: Count depth levels
gh api 'repos/EvanusModestus/domus-captures' | gron | awk -F'.' '{print NF}' | sort -n | uniq -c | sort -rn | head -5
Shows how deep the nesting goes and where most fields live.
Lesson 5: Building a Dashboard
Exercise 5.1: Repo summary from API
gh api 'users/EvanusModestus/repos?per_page=100' |
jq '.[] | select(.name | startswith("domus")) | {name, language, updated: .updated_at, stars: .stargazers_count}' |
jq -s 'sort_by(.updated) | reverse' |
jq -r '.[] | [.name, .language // "none", .updated | split("T")[0], (.stars | tostring)] | @tsv' |
column -t
Exercise 5.2: Attribute inventory across repos
for f in ~/atelier/_bibliotheca/domus-*/docs/asciidoc/antora.yml; do
repo=$(basename "$(dirname "$(dirname "$(dirname "$f")")")")
yq -o=json '.asciidoc.attributes // {}' "$f" |
gron | grep -v '= {}' | wc -l |
xargs -I{} printf "%-30s %s attributes\n" "$repo" "{}"
done
Exercises to Complete
-
[ ] Discover the path to a repo’s license name, then extract it with jq
-
[ ] Build a pipeline: yq reads antora.yml → gron finds VLAN attributes → jq formats as table
-
[ ] Find all null values in a
gh apiresponse for any endpoint -
[ ] Create a one-liner that shows the 5 most recently updated domus repos
Session Log
| Timestamp | Notes |
|---|---|
Start |
<Record when you started> |
End |
<Record when you finished> |