README.md

August 30, 2026 ยท View on GitHub

Twig Logo

Twig ๐ŸŒฟ

Latest release License: MIT CI Buy Me A Coffee

Inspect. Navigate. Understand.
A modern, terminal-based explorer for JSON and YAML files, written in Rust as a single static binary โ€” no Python runtime required.

Twig demo


What is Twig?

Twig is a high-performance terminal UI for exploring JSON and YAML files interactively. It turns deeply nested data into a navigable tree, letting you search, jump, and inspect complex structures without piping commands together or scrolling endlessly.

Twig is designed for understanding data, not editing it. It fills the gap between cat/less (no structure) and heavy IDEs (too slow, GUI-only), making it perfect for production logs, Kubernetes manifests, Terraform state, and large API responses.

Since v3.0.0, Twig is a single ~4 MB static binary with zero runtime dependencies โ€” drop it on any Linux, macOS, or Windows machine and it runs.


Installation

Downloads a prebuilt binary for your platform, verifies its SHA-256 against the GitHub-published *.sha256 file, and installs it to ~/.local/bin (or /usr/local/bin when writable):

curl -fsSL https://twig.wtf/install.sh | sh

Re-running the command safely upgrades an existing install. Useful flags:

# Pin a specific version (e.g. v3.0.0)
curl -fsSL https://twig.wtf/install.sh | sh -s -- --version v3.0.0

# Install to a different directory
curl -fsSL https://twig.wtf/install.sh | sh -s -- --to /usr/local/bin

# Build from source instead of downloading a binary
curl -fsSL https://twig.wtf/install.sh | sh -s -- --method build

# Skip the install confirmation prompt
curl -fsSL https://twig.wtf/install.sh | sh -s -- --yes

The script supports Linux (x86_64, aarch64), macOS (Intel, Apple Silicon), and reports unsupported platforms with a clear error instead of failing silently. Run curl -fsSL https://twig.wtf/install.sh | sh -s -- --help for the full flag list.

Manual download

Grab a prebuilt .tar.gz from the Releases page. Each archive contains a single twig (or twig.exe) binary and a matching *.sha256 checksum file.

Supported targets:

OSArchitectures
Linuxx86_64, aarch64
macOSx86_64 (Intel), aarch64 (Apple Silicon)
Windowsx86_64

Build from source

Requires Rust 1.75 or later:

git clone https://github.com/workdone0/twig.git
cd twig
cargo build --release
./target/release/twig --help

Or install directly from the GitHub repo with cargo install --locked --git https://github.com/workdone0/twig twig. We don't publish to crates.io because that name is taken by an unrelated Rust templating engine โ€” the GitHub-only path keeps the install unambiguous.

Legacy Python version

Twig โ‰ค v2.1.4 was a Python project distributed on PyPI as twg. That implementation is preserved on the legacy-python branch for users who specifically need it. All new installs and active development happen on master, which is the Rust rewrite shipped in v3.0.0.

If you're upgrading from twg:

uv tool uninstall twg                       # remove the old install
curl -fsSL https://twig.wtf/install.sh | sh # install the new binary

No code changes required โ€” twig <file>, twig --fix <file>, and twig --print <file> all work identically, and the persistent config at ~/.config/twig/config.json is shared across both versions.


Usage

# Open a file in the interactive TUI
twig data.json
twig config.yaml

# Pretty-print to stdout (non-TUI, with syntax highlighting)
twig -p large.json

# Repair common JSON malformations (trailing commas, unquoted keys,
# single quotes, NaN/Infinity) and write a clean round-trippable copy
twig --fix broken.json -o clean.json

# Benchmark the streaming ingestion pipeline (non-TUI)
twig --check huge.json

twig --check is non-interactive and prints size, node count, elapsed time, and throughput โ€” useful in CI and ad-hoc perf checks.


Key features

  • ๐Ÿ“‚ Multi-format native: JSON and YAML with the same UI; format is auto-detected from file extension.
  • ๐Ÿ‘€ Read-only by design: Safely explore production secrets without risk of accidental edits.
  • ๐Ÿ” Deep search: Substring search across keys and values, with n / N to jump between matches.
  • ๐Ÿงญ Miller-column navigation: Traverse deep trees with the keyboard, breadcrumbs keep you oriented.
  • ๐ŸŽจ Themes: Catppuccin Mocha (default) and Solarized Dark ship in the box; t cycles. Persistent config at ~/.config/twig/config.json.
  • โšก Streaming ingestion: Constant memory relative to file size โ€” load 10 MB or 10 GB without the process growing.
  • ๐Ÿฉบ Smart inspector: String values get auto-detection for URLs, hex colors, and ISO-8601 timestamps; each gets a side panel.
  • ๐Ÿ“‹ Clipboard actions: c copies the JSONPath, y copies the source slice.

Keyboard shortcuts

ContextActionKey
GeneralQuitq
Help / cheatsheet?
Toggle themet
NavigationMove selectionโ†‘ โ†“ โ† โ†’
Drill in / expandโ†’ Enter l
Step back / collapseโ† Esc h
Jump to top / bottomg G
Jump to path:
SearchGlobal search/
Next / prev matchn N
ActionsCopy pathc
Copy source slicey

Why Twig exists

Many real-world files (API responses, K8s manifests, Terraform state, log exports) contain sensitive information. Pasting them into web-based viewers is a security risk. Existing CLI tools like jq are powerful for transformation but unintuitive for interactive exploration. IDE plugins are heavy and require GUI.

Twig is the missing middle ground:

  • Runs entirely locally โ€” no network calls, no telemetry.
  • Works over SSH and on headless servers.
  • Optimized for reading, not mutation.
  • Single binary โ€” copy it onto a fresh container and it just works.

Compared to alternatives

ToolStrengthLimitation
jqPowerful transformationSteep learning curve for exploration
less / catSimple and universalNo structure awareness
Web viewersVisual and easyPrivacy, size limits, trust issues
IDE pluginsIntegrated with the editorHeavy, GUI-only, can't run over SSH
TwigInteractive, structured, localRead-only, exploration-focused

Non-goals

Twig is not:

  • An editor (use vi / your IDE).
  • A replacement for jq (use jq for transforms).
  • A streaming log viewer (use lnav / less +F).
  • A web service (no server, no API).

Architecture

Built with:

  • ratatui + crossterm โ€” TUI rendering and terminal I/O.
  • rusqlite with bundled SQLite + FTS5 โ€” persistent data store with full-text search.
  • serde_json streaming ingestion โ€” constant memory regardless of file size.
  • serde_yml โ€” YAML parsing.
  • jsonrepair โ€” automatic JSON repair for --fix.
  • arboard โ€” system clipboard with graceful fallback.
  • clap โ€” CLI argument parsing.
  • owo-colors โ€” colored terminal output for --print.

The on-disk cache is a SQLite file with an FTS5 virtual table; old (Python-era) flat-file caches are ignored and rebuilt on first run. There's no migration script because there's nothing to preserve.

Performance

Benchmark on a 50 MB / ~1 M-node synthetic JSON file (cold start, M-class CPU):

BuildLoad timeThroughput
Debug~6 s~8 MB/s
Release (LTO)~16 ms~3 GB/s

Release builds use lto = "thin", codegen-units = 1, strip = "symbols" to get the binary down to ~4 MB.


CLI reference

twig [OPTIONS] <FILE>

Arguments:
  <FILE>   Path to a JSON or YAML file

Options:
  -p, --print            Print pretty-printed output to stdout (non-TUI)
  -o, --output <FILE>    Write output to FILE instead of stdout (with --print or --fix)
  -i, --indent <N>       Indent width for pretty-printed / fixed output [default: 2]
      --fix              Attempt to repair malformed JSON and write a clean copy
      --check            Load the file and print size/node count/throughput stats
      --rebuild-db       Drop the on-disk SQLite cache before loading
      --version          Print version and exit
      --help             Print help and exit

Project layout

.
โ”œโ”€โ”€ Cargo.toml          Rust crate manifest
โ”œโ”€โ”€ Cargo.lock          Locked dependency graph (committed for reproducible builds)
โ”œโ”€โ”€ schema.sql          SQLite schema (nodes + FTS5 virtual table)
โ”œโ”€โ”€ .cargo/config.toml  Cross-compile linker config for aarch64-linux
โ”œโ”€โ”€ src/                Library + binary sources
โ”‚   โ”œโ”€โ”€ main.rs         CLI entry point
โ”‚   โ”œโ”€โ”€ cli/            clap parser, --check, --fix, --print modes
โ”‚   โ”œโ”€โ”€ core/           Node, DataType, paths, store, config, repair
โ”‚   โ”œโ”€โ”€ adapters/       Streaming JSON and YAML loaders
โ”‚   โ””โ”€โ”€ tui/            ratatui app, theme, widgets
โ”œโ”€โ”€ tests/              Integration test suite
โ”œโ”€โ”€ samples/            Test fixtures (k8s manifest, HAR, etc.)
โ”œโ”€โ”€ install.sh          POSIX bash installer (curl | sh)
โ”œโ”€โ”€ asset/              Logo and demo.gif used by README + site
โ””โ”€โ”€ .github/workflows/  CI matrix, release pipeline, auto-tag-on-push

Releasing a new version

The release pipeline is fully automated:

  1. Bump the version field in Cargo.toml and push to master.
  2. .github/workflows/auto-release.yml detects the version change, creates a v<version> tag (idempotent โ€” skips if the tag already exists), and dispatches the release workflow via workflow_dispatch.
  3. .github/workflows/release.yml runs in response: builds Linux x86_64, Linux aarch64 (via cargo-cross), macOS x86_64, macOS aarch64, and Windows x86_64 in parallel; packages each as twig-<triple>.tar.gz with matching *.sha256 files; and publishes them to a GitHub release via softprops/action-gh-release@v2.
  4. curl -fsSL https://twig.wtf/install.sh | sh always picks up the highest-versioned release from the GitHub Releases API.

For a hotfix, push the tag manually (with a PAT, since GITHUB_TOKEN can't fire tag-push events):

git tag v3.0.1
git push origin v3.0.1

Contributing

Contributions welcome. See CONTRIBUTING.md for setup, architecture notes, and submission guidelines.


License

MIT โ€” see LICENSE.