| Crates.io | headson |
| lib.rs | headson |
| version | 0.15.0 |
| created_at | 2025-10-22 07:56:43.560229+00 |
| updated_at | 2026-01-18 23:34:30.753611+00 |
| description | Budget‑constrained JSON preview renderer |
| homepage | https://github.com/kantord/headson |
| repository | https://github.com/kantord/headson |
| max_upload_size | |
| id | 1895286 |
| size | 4,278,526 |
Features · Install · Usage · Python bindings
head/tail for JSON, YAML — but structure‑aware. Get a compact preview that shows both the shape and representative values of your data, all within a strict byte budget. (Just like head/tail, hson can also work with unstructured text files.)
Available as:
auto | json | yaml | text with styles strict | default | detailed--glob ..., or --recursive on directories) with shared or per-file budgetsgrep-like search and tree-like view: --grep <regex> and --tree emulate the workflows while still summarizing file contents inlineFor source code files, headson uses an indentation-aware heuristic to build an outline, then picks representative lines from across that structure (while keeping lines atomic so omissions never split a line). Syntax highlighting is available when colors are enabled.

Learn more: Source code support
Guarantee that matching keys/values stay in view under tight budgets (supports multi-file mode via --glob).

Preview many files at once in a directory tree layout (inline previews, round‑robin fairness; supports multi-file mode via --glob).

In multi-file mode, inputs are ordered so frequently and recently touched files show up first, and rarely touched files drift to the end (using git history when available, with mtime fallback). Use a global byte budget (--global-bytes) to get an up‑to‑date repo snapshot within a strict overall limit (and --chars when you want a per-file character cap).

Using Cargo:
cargo install headson
Note: the package is called
headson, but the installed CLI command ishson. All examples below usehson ....
From source:
cargo build --release
target/release/hson --help
hson [FLAGS] [INPUT...]
Peek a JSON stream from stdin:
curl -sS 'https://pokeapi.co/api/v2/pokemon?limit=151' | hson -c 800
Preview many files with a single total budget:
hson -c 200 -C 1200 logs/*.json
Machine-readable preview (strict JSON):
hson -c 200 -f json -t strict data.json
YAML with detailed comments:
hson -c 400 -f yaml -t detailed config.yaml
Keep matches visible (grep-like) while still summarizing structure:
hson --grep 'error|warning' -c 200 -C 1200 logs/*.json
Tree-like view with inline previews:
hson --tree --glob 'src/**/*' -c 160 -C 1200
Source code outline (keeps lines intact; omits blocks under tight budgets):
hson -n 20 src/main.py
-c, --bytes <BYTES>: per‑file output budget (bytes). For multiple inputs, default total budget is <BYTES> * number_of_inputs.-u, --chars <CHARS>: per‑file output budget (Unicode code points). Behaves like --bytes but counts characters instead of bytes.-C, --global-bytes <BYTES>: total output budget across all inputs. With --bytes, the effective total is the smaller of the two.-f, --format <auto|json|yaml|text>: output format (default: auto).
.json → JSON family, .yaml/.yml → YAML, unknown → Text).-t, --template <strict|default|detailed>: output style (default: default).
strict → strict JSON; default → Pseudo; detailed → JS with inline comments.strict none, default “# …”, detailed “# N more …”).-i, --input-format <json|yaml|text>: ingestion format (default: json). In multi-file mode with --format auto, ingestion is chosen by extensions.-m, --compact: no indentation, no spaces, no newlines--no-newline: single line output--no-header: suppress per-file section headers (useful when embedding output in scripts)--tree: render multi-file previews as a directory tree with inline previews (keeps code line numbers); uses per-file auto formatting.--no-space: no space after : in objects--indent <STR>: indentation unit (default: two spaces)--string-cap <N>: max graphemes to consider per string (default: 500)--grep <REGEX>: guarantee inclusion of values/keys/lines matching the regex (ripgrep‑style). Matches + ancestors are "free" against both global and per-file caps; budgets apply to everything else. If matches consume all headroom, only the must‑keep path is shown. Colors follow the normal on/auto/off rules; when grep is active, syntax colors are suppressed and only the match highlights are colored. JSON/YAML structural punctuation is not highlighted—only the matching key/value text.--igrep <REGEX>: case-insensitive variant of --grep.-r, --recursive: recursively expand directory inputs (like grep -r). Directory paths are required; stdin is not supported. Incompatible with --glob.--head: prefer the beginning of arrays when truncating (keep first N). Strings are unaffected. Display styles place omission markers accordingly; strict JSON remains unannotated. Mutually exclusive with --tail.--tail: prefer the end of arrays when truncating (keep last N). Strings are unaffected. Display styles place omission markers accordingly; strict JSON remains unannotated. Mutually exclusive with --head.Notes:
--no-header to suppress them). In compact/single‑line modes, headers are omitted.--no-sort to keep the original input order without repo scanning.--format auto, each file uses its own best format: JSON family for .json, YAML for .yaml/.yml.
.txt files.--global-bytes may truncate or omit entire files to respect the total budget.--recursive is set; binary files are ignored with a warning. Glob/recursive expansion respects .gitignore plus .ignore/.rgignore. Stdin reads the stream as‑is.--bytes/--chars/--lines) apply to each input; global caps (--global-*) constrain the combined output when set. Default byte/char budgets scale by input count when no globals are set; line caps stay per-file unless you pass --global-lines.--bytes | --chars | --lines) and at most one global flag (--global-bytes | --global-lines). Mixing per-file and global kinds is allowed (e.g., per-file lines + global bytes); conflicting flags error.--glob <PATTERN> to expand additional files, or --recursive to expand directory inputs (incompatible with --glob). Glob patterns are positive-only; use ignore files (.gitignore, .ignore, .rgignore) for exclusions.--no-sort to preserve the order you provided and skip repo scanning.==> headers when newlines are enabled; hide them with --no-header. Compact and single-line modes omit headers automatically.--format auto, each file picks JSON/YAML/Text based on extension; unknowns fall back to Text so mixed inputs “just work.”{} like valid empty objects.Use --grep <REGEX> to guarantee inclusion of values/keys/lines matching the regex (ripgrep-style). Matches plus their ancestors are "free" against budgets; everything else must fit the remaining headroom.
--no-color.--grep foo --grep bar matches "foo" or "bar".--igrep <REGEX> for case-insensitive matching. Can be combined with --grep: --grep Foo --igrep bar matches "Foo" (exact case) or "bar"/"BAR"/"Bar" (any case).--weak-grep <REGEX> biases priority toward matches but does not guarantee inclusion, expand budgets, or filter files. Budgets stay exact and matches can still be pruned if they do not fit. Use --weak-igrep <REGEX> for case-insensitive weak grep. Weak grep can be combined with strong grep: strong matches are guaranteed while weak matches are prioritized.--grep only):
--grep-show=matching): files without matches are dropped from the render and summary. If no files match at all, the output is empty and the CLI prints a warning to stderr.--grep-show=all: keep non-matching files in the render; only matching files are highlighted.--no-header as usual.--grep-show requires --grep or --igrep.-C/-B/-A style flags; per-file budgets decide how much surrounding structure/lines can stay alongside the must-keep matches.-i text and source code files; when using --format auto, file extensions still decide ingest/rendering.Use --tree to render multi-file output as a directory tree (like tree) with inline structured previews instead of per-file headers. Works with grep/weak-grep; matches are shown inside the tree.
├─, │, └─) with continuous guides; code gutters stay visible under the tree prefix.--tree is mutually exclusive with --no-header; tree mode never prints ==> headers and relies on the tree structure instead. Files are still auto-formatted per extension (--format must be auto in multi-file mode).--count-headers); per-file budgets always apply to file content and omission markers, and global caps apply only when provided. Tight budgets can truncate file previews within the tree, and entire files may be omitted under tiny global line budgets—omitted entries are reported as … N more items on the relevant folder/root. When scaffold is free, the final output can exceed the requested caps by the tree gutters/indentation; set --count-headers if those characters must be bounded.--no-sort; otherwise uses the usual repo-aware ordering (frequent+recent first; mtime fallback) before tree grouping.Bytes (-c/--bytes, -C/--global-bytes)
--lines nor --chars is provided.<BYTES> * number_of_inputs; --global-bytes caps the total.Characters (-u/--chars)
Lines (-n/--lines, -N/--global-lines)
--no-newline.<LINES> is enforced per file; add --global-lines if you also need an aggregate cap.-H/--count-headers to include headers/summaries in the line budget.… for text/code, {…}/[…] for objects/arrays); a single-line file still renders when it fits.Interactions and precedence
-n 0 semantics). Extremely tight nonzero caps that cannot fit even an omission marker can also yield empty output; multi-file/tree output may show only omission counts in that scenario.Single file (auto):
hson -c 200 notes.txt
Force Text ingest/output (useful when mixing with other extensions, or when the extension suggests JSON/YAML):
hson -c 200 -i text -f text notes.txt
# Force text ingest even if the file looks like JSON
hson -i text notes.json
Styles on Text:
… line.… N more lines ….…).Note: In multi-file mode, each file uses its own auto format/template. When you need to preview a directory of mixed formats, skip
-f textand let-f autopick the right renderer for each entry.
For source code files, headson uses an indentation-aware heuristic to build an outline, then samples representative lines from across that structure.
Show help:
hson --help
Note: flags align with head/tail conventions (-c/--bytes, -C/--global-bytes).
Input:
{"users":[{"id":1,"name":"Ana","roles":["admin","dev"]},{"id":2,"name":"Bo"}],"meta":{"count":2,"source":"db"}}
If you head -c a JSON file/stream, you can cut it in the middle of a value and end up with a confusing snippet:
head -c 80 users.json
# {"users":[{"id":1,"name":"Ana","roles":["admin","dev"]},{"id":2,"name":"Bo"}],"me
With hson, you still get a compact preview, but it stays structure-aware:
hson -c 120 -f json -t default users.json
# {
# users: [
# { id: 1, name: "Ana", roles: [ "admin", … ] },
# …
# ]
# meta: { count: 2, … }
# }
If you need machine-readable output, use strict mode:
hson -c 120 -f json -t strict users.json
# {"users":[{"id":1,"name":"Ana","roles":["admin"]}],"meta":{"count":2}}
A thin Python extension module is available on PyPI as headson.
pip install headson (ABI3 wheels for Python 3.10+ on Linux/macOS/Windows).
API:
headson.summarize(text: str, *, format: str = "auto", style: str = "default", input_format: str = "json", byte_budget: int | None = None, skew: str = "balanced") -> str
format: "auto" | "json" | "yaml" (auto maps to JSON family for single inputs)style: "strict" | "default" | "detailed"input_format: "json" | "yaml" (ingestion)byte_budget: maximum output size in bytes (default: 500)skew: "balanced" | "head" | "tail" (affects display styles; strict JSON remains unannotated)Examples:
import json
import headson
data = {"foo": [1, 2, 3], "bar": {"x": "y"}}
preview = headson.summarize(json.dumps(data), format="json", style="strict", byte_budget=200)
print(preview)
# Prefer the tail of arrays (annotations show with style="default"/"detailed")
print(
headson.summarize(
json.dumps(list(range(100))),
format="json",
style="detailed",
byte_budget=80,
skew="tail",
)
)
# YAML support
doc = "root:\n items: [1,2,3,4,5,6,7,8,9,10]\n"
print(headson.summarize(doc, format="yaml", style="default", input_format="yaml", byte_budget=60))
docs/diagrams/algorithm.mmd. Regenerate the SVG with cargo make diagrams before releasing.head/tail: byte/line-based, so output often breaks structure in JSON/YAML or surfaces uninteresting details.jq: powerful, but you usually need to write filters to get a compact preview of large JSON.MIT