RepoPilotOpen in app →

tomnomnom/gron

Make JSON greppable!

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 11mo ago
  • 20 active contributors
  • MIT licensed
Show 4 more →
  • CI configured
  • Tests present
  • Slowing — last commit 11mo ago
  • Concentrated ownership — top contributor handles 70% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tomnomnom/gron)](https://repopilot.app/r/tomnomnom/gron)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tomnomnom/gron on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tomnomnom/gron

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tomnomnom/gron shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 11mo ago
  • 20 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 11mo ago
  • ⚠ Concentrated ownership — top contributor handles 70% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tomnomnom/gron repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tomnomnom/gron.

What it runs against: a local clone of tomnomnom/gron — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tomnomnom/gron | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 373 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tomnomnom/gron</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tomnomnom/gron. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tomnomnom/gron.git
#   cd gron
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tomnomnom/gron and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tomnomnom/gron(\\.git)?\\b" \\
  && ok "origin remote is tomnomnom/gron" \\
  || miss "origin remote is not tomnomnom/gron (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "main.go" \\
  && ok "main.go" \\
  || miss "missing critical file: main.go"
test -f "statements.go" \\
  && ok "statements.go" \\
  || miss "missing critical file: statements.go"
test -f "ungron.go" \\
  && ok "ungron.go" \\
  || miss "missing critical file: ungron.go"
test -f "token.go" \\
  && ok "token.go" \\
  || miss "missing critical file: token.go"
test -f "identifier.go" \\
  && ok "identifier.go" \\
  || miss "missing critical file: identifier.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 373 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~343d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tomnomnom/gron"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

gron transforms JSON into line-by-line assignment statements (e.g., json.contact.email = "mail@tomnomnom.com"), making it greppable and path-addressable. It solves the core problem of exploring large, undocumented JSON APIs by letting you grep for values and immediately see their full object path, then reconstruct filtered JSON with --ungron mode. Single-binary architecture: main.go is the entry point orchestrating two main flows—gron (JSON→statements via statements.go) and ungron (statements→JSON via statements.go). identifier.go handles path/variable name parsing and validation. Minimal dependencies; testdata/ contains integration test fixtures (one.json, github.json, big.json).

👥Who it's for

API developers and DevOps engineers who need to quickly explore JSON responses from third-party APIs with poor documentation, or anyone who wants to filter/extract specific fields from large JSON blobs using standard Unix tools like grep and awk.

🌱Maturity & risk

Production-ready and stable. The project has comprehensive test coverage (identifier_test.go, main_test.go, statements_test.go), CI/CD pipelines via GitHub Actions (.github/workflows/build.yml, release.yml), and goreleaser configuration for multi-platform binaries. Last evidence of maintenance includes Go 1.24 compatibility in go.mod and no breaking changes in recent releases based on CHANGELOG.mkd.

Very low risk. Only 5 dependencies (fatih/color, mattn/go-colorable, nwidger/jsoncolor, pkg/errors, golang.org/x/sys), all well-maintained libraries. Single author (tomnomnom) with no major structural breaking changes visible. Small codebase (~67KB Go code) means easy to audit and reason about. Main risk is feature-freeze: project appears stable but not actively adding features.

Active areas of work

No active development visible—repository appears in maintenance mode. Last changes likely stabilized the Go module (go 1.24 support) and shell completion files (gron.bash, gron.fish). No open issues or PRs mentioned in provided metadata; focus is on stability and bug fixes rather than new features.

🚀Get running

git clone https://github.com/tomnomnom/gron.git
cd gron
go build -o gron .
./gron testdata/one.json

Daily commands:

go run . testdata/one.json
go run . < testdata/one.json
go run . https://api.github.com/repos/tomnomnom/gron
go run . --ungron < testdata/one.gron

🗺️Map of the codebase

  • main.go — Entry point containing CLI argument parsing and orchestration of gron (forward) and ungron (reverse) transformations.
  • statements.go — Core logic for converting JSON to discrete gron statements; implements the primary transformation algorithm.
  • ungron.go — Reverses gron statements back into JSON; essential for the bidirectional functionality advertised in README.
  • token.go — Lexical tokenization layer that parses gron statement syntax; foundation for ungron parsing.
  • identifier.go — Handles validation and escaping of JSON keys as valid Go identifiers in gron output format.
  • url.go — Fetches JSON from HTTP URLs directly; enables gron to work with remote API responses out-of-the-box.

🧩Components & responsibilities

  • statements.go (encoding/json, bufio, fmt) — Recursively traverses JSON AST and emits path=value statements; heart of forward transformation.
    • Failure mode: Panic on deeply nested structures (no depth limit); memory spikes on very large objects.
  • ungron.go (token.go, map, reflect (type assertion)) — Parses gron statements line-by-line and reconstructs JSON tree; heart of reverse transformation.
    • Failure mode: Silent truncation if conflicting path assignments detected; no merge strategy defined.
  • token.go (bufio, rune-based scanning) — Lexical analyzer for gron syntax; converts text into token stream for ungron parser.
    • Failure mode: Crashes on unexpected escape sequences; poor error messages for malformed input.
  • url.go (net/http, io.Reader) — Fetches JSON from HTTP URLs; transparent integration into main CLI.
    • Failure mode: Hangs on slow/unresponsive servers (no timeout); large responses exhausts memory.
  • identifier.go (unicode, strings) — Validates and escapes JSON object keys for safe representation in gron paths.
    • Failure mode: Over-escaping non-ASCII characters; round-trip may not preserve original key formatting.

🔀Data flow

  • CLI arguments / stdinmain.go — User provides URL, file path, or JSON directly; main.go parses flags and input source.
  • main.gourl.go (if URL) or encoding/json.Unmarshal (if file/stdin) — Main dispatches to appropriate data source; retrieves raw JSON bytes.
  • JSON bytesencoding/json.Unmarshal → any — Parsed into generic interface{} (tree of maps and slices).
  • Interface tree (forward path)statements.go — Recursive walk emits gron statements to stdout or filter buffer.
  • Gron statements (reverse path, via stdin/file)token.go — Each line tokenized into tokens (path, operator, value).
  • Token streamungron.go — Parser reconstructs nested map/slice structure from path assignments.
  • Reconstructed JSON treeencoding/json.Marshal → stdout — Final JSON serialized with optional colorization (jsoncolor).

🛠️How to make changes

Add a new output format (e.g., YAML gron representation)

  1. Create a new output function in statements.go following the pattern of existing formatters (statements.go)
  2. Add a new CLI flag in main.go (e.g., --yaml-gron) and dispatch logic (main.go)
  3. Write tests mirroring main_test.go structure with expected output (main_test.go)

Add a new token type for extended syntax (e.g., regex filters)

  1. Define new TokenType constant in token.go (token.go)
  2. Extend the lexer function to recognize and emit the new token (token.go)
  3. Update ungron.go parser to handle the new token in statement parsing (ungron.go)
  4. Add test cases in token_test.go and ungron_test.go (token_test.go)

Support fetching JSON from a new source type (e.g., S3 bucket)

  1. Add detection logic in url.go (e.g., recognize s3:// scheme) (url.go)
  2. Implement fetcher function for the new source type in url.go (url.go)
  3. Wire the fetcher into main.go's argument processing (main.go)
  4. Add integration test in url_test.go (url_test.go)

🔧Why these technologies

  • Go (language) — Fast, minimal runtime dependency, single cross-platform binary; perfect for command-line tooling and exploring large JSON payloads efficiently.
  • Recursive descent parsing (token.go, ungron.go) — Simple and sufficient for gron's context-free grammar; avoids heavyweight parser generators for a lightweight tool.
  • Standard library I/O (bufio, encoding/json) — Zero external dependencies for core logic; streaming support via bufio for large files; native JSON marshaling.
  • fatih/color + jsoncolor (output formatting) — Terminal color output for readability; jsoncolor provides syntax highlighting of reconstructed JSON in ungron mode.

⚖️Trade-offs already made

  • Single-pass JSON traversal in statements.go (forward gron)

    • Why: Memory efficient; avoids building intermediate AST for large JSON
    • Consequence: Cannot easily add filters or transformations post-traversal; CLI flags must be decided before walking.
  • Line-by-line gron statement parsing in ungron.go

    • Why: Supports streaming/piping workflows; matches grep/filter use case in README
    • Consequence: Ungron cannot detect structural conflicts until all lines processed; errors reported late.
  • Identifier escaping in identifier.go (backslash-escape for special chars)

    • Why: Keeps gron statements readable and grep-friendly without quoting all keys
    • Consequence: Keys with backslashes themselves require escaping; slightly non-standard vs JSON.
  • No schema validation or type hints

    • Why: Gron is exploratory; minimal assumptions about JSON structure
    • Consequence: Type mismatches (assigning string to number) only caught on ungron rebuild.

🚫Non-goals (don't propose these)

  • Real-time streaming of large API responses (works but single-buffered, not true streaming)
  • Custom filtering syntax (use grep/fgrep instead; gron is a data format tool, not a query language)
  • Support for non-JSON data formats (YAML, XML, etc.)
  • Authentication or credential management (users must handle API keys externally)

⚠️Anti-patterns to avoid

  • Unbounded recursion in statements.go walk() (Medium)statements.go: No depth limit on recursive JSON traversal; pathological inputs (deeply nested or circular refs) can cause stack overflow.
  • Silent data loss in ungron on conflicting pathsungron.go: When two gron statements assign conflicting types to the same path (e.g., json.a = {} then json.a =

🪤Traps & gotchas

No required environment variables or external services. One subtle gotcha: the ungron parser is line-order-sensitive—statements must be in the correct order for reconstruction. Another: URL fetching (main.go) silently assumes HTTP/HTTPS; file:// URIs are not explicitly documented but may be supported. Bareword vs. quoted identifier rules in identifier.go can trip up when reconstructing JSON with special characters in keys.

🏗️Architecture

💡Concepts to learn

  • Recursive descent into JSON structures — gron's core algorithm walks the JSON tree recursively, building dot-notation paths; understanding this recursion is key to modifying the flattening logic in statements.go
  • Identifier validation and quoting rules — gron must decide when to quote keys (json["User-Agent"] vs json.name) based on Go identifier rules; this drives the identifier.go module and affects round-trip correctness
  • Statement reconstruction from filtered output — ungron must parse gron statements back into valid JSON, requiring careful order-sensitive reconstruction and type inference from assignment syntax
  • ANSI escape codes for terminal coloring — gron uses fatih/color to highlight syntax (paths, values, operators) in terminal output; understanding color codes helps debug output rendering
  • Grepping and piping Unix philosophy — gron's entire design assumes line-by-line output that pipes into grep, awk, and other text tools; this shapes the statement format and output ordering
  • HTTP client state and URL handling — main.go can fetch JSON directly from URLs; understanding Go's net/http package and URL parsing is needed for the remote fetch feature
  • stedolan/jq — Industry-standard JSON query and transformation tool; gron is complementary for grep-based exploration where jq is for complex transformations
  • jqlang/jq — Modern Go-based reimplementation of jq; shares the same problem domain (JSON manipulation) but with a different API model
  • itchyny/gojq — Another jq clone in Go; explores the same JSON manipulation space with Go portability
  • tomnomnom/asciitree — Sibling project by same author; complements gron by visualizing hierarchical data in tree format rather than line-by-line
  • rakyll/hey — HTTP load testing tool by Go ecosystem developer; often used with gron to explore API responses before benchmarking

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for URL input handling (url.go)

The repo supports fetching JSON from URLs (as shown in the README example with api.github.com), but url_test.go likely has minimal coverage. Given that gron is a CLI tool that processes remote APIs, URL validation, error handling, and edge cases (timeouts, redirects, malformed URLs) are critical. This would improve reliability for users fetching from real APIs.

  • [ ] Examine url.go and url_test.go to identify missing test cases
  • [ ] Add tests for: invalid URLs, network timeouts, HTTP error codes (4xx, 5xx), redirect chains, and empty responses
  • [ ] Test that color output and ungron modes work correctly with remote URLs
  • [ ] Add tests for URL edge cases (special characters, very long URLs, non-standard ports)

Add GitHub Actions workflow for automated releases and cross-platform testing

The repo has .goreleaser.yml and .travis.yml (deprecated CI), but the .github/workflows directory only contains build.yml and release.yml. Adding a comprehensive GitHub Actions workflow that tests against multiple Go versions (1.20, 1.21, latest) and builds/tests on Linux, macOS, and Windows would modernize the CI/CD and catch platform-specific bugs early. This is especially important for a CLI tool.

  • [ ] Create .github/workflows/test.yml that runs tests on Go 1.20, 1.21, and latest across ubuntu-latest, macos-latest, and windows-latest
  • [ ] Add test coverage reporting and upload to a service like Codecov
  • [ ] Verify the release.yml workflow integrates properly with the new test workflow
  • [ ] Test that shell completions (gron.bash, gron.fish) are validated in CI

Add parser error recovery and detailed error messages for invalid gron syntax

The token.go and statements.go files handle parsing, but testdata includes invalid-type-mismatch.gron and invalid-value.gron. Currently, users likely get cryptic parser errors when they use incorrect gron syntax. Adding informative error messages with line numbers and hints (similar to modern compilers) would drastically improve the developer experience when debugging gron statements.

  • [ ] Review token.go and statements.go to understand current error handling
  • [ ] Add position tracking (line and column numbers) to token.go
  • [ ] Enhance error messages in ungron.go to show context (e.g., 'Invalid assignment at line 5: expected value after =')
  • [ ] Add test cases in ungron_test.go for error messages covering: syntax errors, type mismatches, malformed paths, and incomplete statements

🌿Good first issues

  • idea: Add --sort flag to gron output so paths are sorted lexicographically, making diffs and comparisons easier. This would be a small addition to statements.go's output loop in main.go.
  • idea: Extend identifier.go to handle more edge cases in JSON key validation (e.g., keys starting with numbers, very long keys). Add test cases to identifier_test.go for these scenarios.
  • idea: Add --slurp mode (like jq -s) to read multiple JSON objects from stdin and gron each as json[0], json[1], etc. This would be a preprocessor in main.go before calling statements.Parse().

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 88a6234 — Merge pull request #128 from rwky/master (tomnomnom)
  • 500da07 — Multiple changes (Rowan Wookey)
  • 5ed5e70 — Updates github build action (tomnomnom)
  • a8e5b19 — Adds value mode parse error; fixes #117 (tomnomnom)
  • 3428fe8 — Merge pull request #101 from dotcs/feature/proxy (tomnomnom)
  • 15253ea — Merge pull request #100 from dotcs/bugfix/version-number (tomnomnom)
  • dc84349 — Merge pull request #83 from JohnMcLear/github-ci (tomnomnom)
  • 2fd5f51 — Merge pull request #123 from jamessimas/travis_ci (tomnomnom)
  • f30a783 — Merge pull request #99 from dotcs/feature/arm-build-target (tomnomnom)
  • 695525b — Merge pull request #84 from knowledgejunkie/patch-1 (tomnomnom)

🔒Security observations

The codebase has a solid security posture with minimal critical vulnerabilities. Main concerns are: (1) an unusual/future Go version declaration requiring verification, (2) reliance on a deprecated error handling library that should be modernized, and (3) moderate-severity considerations around URL and JSON input handling that should be hardened with validation and limits. No hardcoded secrets, SQL injection, XSS, or serious misconfigurations detected. Dependencies are from reputable sources with reasonable maintenance history (except pkg/errors).

  • Medium · Outdated Go Version — go.mod. The project specifies Go 1.24 in go.mod, which is a future/unreleased version. This could indicate version mismatch issues or potential compatibility problems. Standard practice is to use stable, released versions. Fix: Use a stable, released Go version (e.g., go 1.21 or go 1.22). Verify the actual Go version used in CI/CD pipelines matches the declared version.
  • Low · Dependency on pkg/errors (Deprecated) — go.mod. The package github.com/pkg/errors v0.9.1 is no longer actively maintained. Go 1.13+ provides native error wrapping with fmt.Errorf and errors.Is/As, making this dependency unnecessary. Fix: Replace github.com/pkg/errors with Go's native error handling. Update code to use fmt.Errorf with %w verb and errors package functions.
  • Low · Potential Command Injection via URL Processing — url.go, main.go. The application accepts URLs as command-line arguments (visible in README: gron "https://api.github.com/..."). If the url.go module processes URLs without proper validation or escaping, this could pose injection risks when URLs are used in shell commands or HTTP requests. Fix: Ensure URL parsing uses Go's standard net/url package. Validate and sanitize URL schemes and hosts. Never pass URLs directly to shell commands. Use proper HTTP client libraries for requests.
  • Low · Unvalidated JSON Processing — main.go, statements.go. The application processes JSON from external sources (APIs). While JSON unmarshaling itself is safe, large JSON files could be exploited for DoS attacks (as evidenced by testdata/big.json). Fix: Implement size limits on input JSON. Set maximum recursion depth limits when parsing. Add timeouts for network requests to external APIs.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tomnomnom/gron — RepoPilot