dataverse
Find a file
JMARyA aa19a598a5
Some checks failed
ci/woodpecker/push/rust-test/3 Pipeline was successful
ci/woodpecker/push/rust-test/1 Pipeline was successful
ci/woodpecker/push/rust-test/2 Pipeline was successful
ci/woodpecker/push/container/2 Pipeline was successful
ci/woodpecker/push/container-manifest unknown status
ci/woodpecker/push/container/1 Pipeline failed
feat: add schema inference command and move IR to jsaw-core
Adds `jsaw schema <dir>` — scans a directory of structured files and
infers a common schema with field coverage, semantic types, required
detection and enum inference for low-cardinality fields.

Core inference logic (FieldSchema IR, infer_schema, infer_schema_filtered)
lives in jsaw-core::schema so downstream crates (e.g. mdq) can consume it
without pulling in the TUI. The jsaw-bin command provides an interactive
ratatui TUI with collapsible nested fields and a detail popup, plus CSV
output when piped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:02:01 +01:00
.hooks split into workspace for core, bin, and gui components 2026-03-01 11:37:05 +01:00
.woodpecker fix: ci 2026-03-02 22:20:47 +01:00
jsaw-bin feat: add schema inference command and move IR to jsaw-core 2026-03-04 09:02:01 +01:00
jsaw-core feat: add schema inference command and move IR to jsaw-core 2026-03-04 09:02:01 +01:00
jsaw-gui chore(version): v0.2.0 2026-03-01 11:40:32 +01:00
.gitignore chore: nix pkg output 2025-11-10 13:49:59 +01:00
AGENTS.md init 2025-11-09 03:26:21 +01:00
Cargo.lock feat: add schema inference command and move IR to jsaw-core 2026-03-04 09:02:01 +01:00
Cargo.toml add db feature + csv 2026-03-01 11:37:53 +01:00
cog.toml chore: add cog 2025-11-27 23:34:46 +01:00
flake.lock fix: recent dioxus 2025-11-26 18:01:44 +01:00
flake.nix feat: add schema inference command and move IR to jsaw-core 2026-03-04 09:02:01 +01:00
justfile split into workspace for core, bin, and gui components 2026-03-01 11:37:05 +01:00
README.md docs: mark inspect TUI as implemented in roadmap 2026-03-01 12:33:08 +01:00
renovate.json chore: add renovate.json 2025-11-12 20:00:56 +00:00

jsaw

A universal runtime for structured data.

JSON, TOML, YAML, Markdown frontmatter, CSV — one tool to inspect, query, validate, convert, and browse them all. Unix-friendly by default; a rich TUI when you want to think.


Install

# Nix (recommended)
nix run github:yourusername/jsaw

# From source (CLI only)
cargo install --path jsaw-bin

CLI

Composable, pipeable, scriptable. Every command reads from a file or - for stdin.

jsaw inspect <file|->               # type tree: keys, depths, value types
jsaw validate <path> [--schema <f>] # JSON Schema validation; auto-detects $schema
              [--recursive]         # walk a whole directory
              [--skip-unparseable]  # silently skip unreadable files
              [--quiet]             # only print failures
jsaw query <file|-> <expr>          # jq-style filter via jaq
              [--raw]               # raw string output, no JSON quoting
jsaw convert <file> --to <fmt>      # json | toml | yaml
              [--out <file>]        # write to file instead of stdout
jsaw fmt <file> [--in-place]        # pretty-print in original format
jsaw db <dir> [-c col] [-f filter]  # directory as queryable table → TUI or CSV
              [-s field] [-r]       # sort, reverse
              [--offset N] [-l N]   # pagination
              [--json]              # output as JSON instead

Piping examples:

cat secrets.yaml | jsaw query - '.tokens[]'
jsaw db ./posts -c "title" -c "date" -f '.published == true' -s date -r
jsaw validate ./schemas/ --recursive --skip-unparseable --quiet

TUI

jsaw db <dir> launches a TUI automatically when stdout is a terminal. This is the primary interactive surface of jsaw — the place where you think with your data, not just read it.

Current state

The TUI launches automatically when jsaw db is run in a terminal. It is a full state machine with four modes:

Table mode — the default view:

  • j/k ↑/↓ — move row; g/G — first/last; PgUp/PgDn — page
  • s / S — cycle sort column / reverse; active sort shown as / in header
  • / — open live filter bar (jq predicate, applied instantly on Enter)
  • Enter — open detail view for selected row
  • ? — help overlay; q/Esc — quit

Filter bar — activated with /:

  • Type any jq predicate (e.g. .active == true, .score > 50)
  • Enter applies; Esc cancels; Ctrl+U clears; Ctrl+Backspace deletes word

Detail view — full record tree activated with Enter:

  • Collapsible tree: Space/Enter fold/unfold; j/k scroll; q/Esc back
  • Virtual file branch shows filesystem metadata (name, path, size, mtime…)
  • data branch shows the full record with type badges on the right

Semantic rendering — every value is classified and colored:

Semantic type Display
URL cyan + underline
Email cyan
DateTime yellow
Date yellow
Boolean green ✓ / red ✗
Integer / Float magenta
UUID blue
Color (#rrggbb) rendered in its own RGB foreground color
SemVer green
File path yellow
IP address blue
Base64 dim, truncated to preview
Markdown first line only +
GeoJSON geometry green badge with shape name
JSON Schema cyan badge
Null dim

The inference engine (jsaw-core::semantic) is value-first (URL scheme, ISO-8601, UUID format, GeoJSON shape check, base64 alphabet, markdown signals) with key-name heuristics as fallback (url/href/link → Url, email/mail → Email, date/created → Date, etc.).


Roadmap

Checked items are implemented. Everything else is planned.

Table view (jsaw db)

  • Basic table rendering with auto-column detection
  • Row navigation (vim keys + arrows, g/G, PgUp/PgDn)
  • Status bar with row count and hints
  • Live filter bar/ opens a jq predicate bar; Enter applies, Esc cancels
  • Column sorts cycles sort column, S reverses; / shown in header
  • Semantic cell rendering — values colored and formatted by inferred type
  • Row detail panelEnter opens full-screen collapsible tree for selected row
  • Help overlay? shows all keybindings in a centered popup
  • Column picker — press C to toggle visible columns interactively
  • Fuzzy search — press f for cross-column fuzzy match
  • Export — press e to write current filtered/sorted view as JSON or CSV
  • Clipboard yank — press y to copy selected cell value
  • Multi-sort — stack sort keys, not just one
  • Column resize — keyboard-resize columns

Tree / inspect view (jsaw inspect)

Currently inspect only prints and exits. The goal: when stdout is a terminal, jsaw inspect should open a navigable tree TUI. The semantic engine and collapsible tree code from the detail view are already reusable for this.

  • Semantic type inference — engine exists in jsaw-core::semantic, shared with the TUI
  • Collapsible tree — implemented in detail view; needs to be the primary view for inspect
  • Type-colored values — implemented in styled_value()
  • inspect launches TUI — opens the collapsible tree viewer when stdout is a terminal; falls back to plain-text print when piped
  • Search — press / to jump-to-key or search values
  • Schema overlay — if $schema is present, show field descriptions, required markers, enum hints
  • Clipboard yanky copies the value at cursor as JSON
  • JQ bar — press : to run a jq expression and show results in a result pane
  • Jump to path — press g followed by a dot-path like .dependencies.ratatui

General TUI improvements

  • Watch mode--watch flag, auto-reload and re-render when file changes on disk
  • Mouse support — click to select rows/cells, scroll with wheel
  • Theme / color config — respect NO_COLOR, allow minimal / full-color modes
  • Error pane — show parse or schema errors non-fatally in a dismissible panel
  • Diff modejsaw diff <file-a> <file-b> opens a side-by-side TUI diff

Longer-term / bigger ideas

  • Multi-file pane — open multiple files as tabs, navigate between them
  • Edit mode — press e in tree view to edit a value inline; write back to file
  • Schema-driven edit — constrained editing when a schema is present (enums as pickers, required fields enforced)
  • Cross-file linking — navigate from a foreign-key value to the referenced file/record
  • HTTP sourcejsaw inspect https://api.example.com/data fetches and renders live
  • Graph view — detect graph-shaped data and render a force-directed node graph in the terminal (sixel / unicode blocks)

Philosophy

  • Schema-first, not schema-required — schemas unlock contextual rendering, validation, and intelligent editing. jsaw degrades gracefully when none exists.
  • The UI is a lens, never the owner — files stay files. TOMLs stay TOMLs. jsaw never holds your data hostage.
  • Inference over annotation — a field named url with a URI value doesn't need to be tagged as a link. It already is one.
  • Unix-friendly — every command pipes in, pipes out. The TUI is opt-in, not mandatory.
  • TUI first — the terminal is the right home for a developer data tool. Fast to open, keyboard-driven, scriptable context around it.

GUI

There is a Dioxus desktop GUI (jsaw-gui) in this repo. It is currently experimental and secondary. The plan is to validate interactions and rendering ideas in the TUI first, then port proven patterns to the GUI. Don't rely on the GUI for production use yet.


Architecture

jsaw/
├── jsaw-core/     # shared logic: data loading, filtering, records, schema
├── jsaw-bin/      # CLI binary (clap); TUI lives here (ratatui + crossterm)
└── jsaw-gui/      # Dioxus desktop app (experimental)

jsaw-core has no UI dependencies. jsaw-bin and jsaw-gui both depend on it. TUI features implemented in jsaw-bin can be reasoned about and ported to jsaw-gui later — the core data model is shared.


Development

# Full workspace (requires Nix devshell for jsaw-gui's native deps)
just check

# CLI only (no Nix required, but needs libiconv on macOS)
cargo run -p jsaw-bin -- db ./some-dir

# TUI dev loop
cargo run -p jsaw-bin -- db ./testdata

# GUI (Nix devshell)
cd jsaw-gui && nix develop ..#default --command dx serve