Skip to main content

gracefall

Fallback-first graphics for terminals. One byte stream, two renderings.

Every chart gracefall emits is wrapped in an OSC 4700 envelope carrying the underlying data, with generated unicode fallback text as the envelope's visible body. Terminals that don't know the protocol silently swallow the envelope and show the fallback, which is already a real visualization. A terminal that implements OSC 4700 re-renders the same cells as smooth, theme-aware vector graphics.

the same bytes in a plain terminal and in an implementing terminal

The left panel is what gracefall demo shows in every terminal on earth today, including macOS Terminal.app over SSH inside tmux. The right panel is the same bytes in a terminal that implements the protocol. Nothing else in the terminal ecosystem has this property: sixel prints garbage on a miss, kitty graphics needs a query round trip, and both lose selection, grep, scrollback, and screen readers. Here the fallback IS the text, so all of that keeps working by construction.

gracefall running in a terminal with no graphics support

That recording is a plain xterm-256color, so every chart in it is the fallback text. The envelopes are being emitted the whole time and the terminal is silently swallowing them, which is the entire design: emitting is safe blind.

Install

uv tool install gracefall     # or: pipx install gracefall

Zero dependencies, pure stdlib Python 3.9+. gfl is installed as a short alias for gracefall.

Use

seq 1 20 | gracefall spark
gracefall meter 62% -c amber
gracefall flow build:done test:done canary:active prod:pending
gracefall dist --bins 20 < latencies.txt
paste xs.txt ys.txt | gracefall scatter
gracefall demo

Pipe-safety is automatic: envelopes are emitted only when stdout is a tty, so gracefall spark ... | less and shell captures get pure fallback. Use --force-osc to save a stream and --no-osc to strip unconditionally.

gracefall demo --force-osc > examples/inference.gfall
cat examples/inference.gfall        # safe in any terminal, try it
grep "kv cache" examples/inference.gfall
gracefall render examples/inference.gfall -o enhanced.svg
gracefall render examples/inference.gfall --plain -o plain.svg

render is the reference renderer: executable semantics for terminal authors, and the thing CI uses to verify the emitter.

Seeing the smooth rendering today

No terminal implements OSC 4700 yet, so gfl view stands in for one. It works out where each span's cells landed, rasterizes the span, and places the image over exactly those cells using the kitty graphics protocol, which Ghostty, kitty, and WezTerm already speak:

uv tool install "gracefall[view]"     # or: pipx install "gracefall[view]"
gracefall demo --force-osc | gfl view

Always on

gfl shell runs your normal shell inside gracefall. Every program you run is unmodified and unaware, and anything that emits gracefall envelopes is rendered as it scrolls past, with nothing to pipe:

gfl shell
# your usual prompt, your usual shell. Now any chart any tool emits is drawn.
exit    # back to the shell you started from

It works by watching the byte stream and counting the cells each fallback writes, so it knows where a chart landed without emulating a terminal. If anything happens mid-span that it does not model, it leaves the fallback alone rather than painting in the wrong place.

gfl view --watch 'some command' re-runs the command on an interval and repaints in place, and gracefall render file.gfall --png composes the same picture to a PNG without needing a terminal at all, which is how the image above is generated.

In a terminal without graphics support the same command prints the fallback text unchanged and one line on stderr saying why. Inside tmux it does the same, because tmux drops the graphics sequences unless you run tmux set -g allow-passthrough on. The geometry comes from the same module the SVG renderer uses, so the shim cannot drift from the reference rendering. Notes on how it works, and its limits under tmux and scrollback, are in docs/view-notes.md.

Recipes

Real commands, not the demo. Each one is a live reading of your machine.

# disk usage
df -H /System/Volumes/Data | awk 'NR==2{gsub(/%/,"",$5); print $5/100}' \
  | xargs -I{} gracefall meter {} -c amber -w 30

# memory used
vm_stat | awk '/Pages free/{f=$3} /Pages active/{a=$3} /Pages wired/{w=$4} \
  END{gsub(/\./,"",f); gsub(/\./,"",a); gsub(/\./,"",w); print (a+w)/(a+w+f)}' \
  | xargs -I{} gracefall meter {} -c violet

# cpu% across the busiest processes
ps -A -o %cpu | tail -n +2 | sort -rn | head -30 | gracefall spark -c teal

# commits per day, last 30 days
git log --since=30.days --format=%ad --date=short | sort | uniq -c \
  | awk '{print $1}' | gracefall spark -c violet

# request latency from a log, as a histogram
awk '{print $NF}' access.log | gracefall dist --bins 30

# deploy status
gracefall flow build:done test:done canary:active prod:pending

examples/sysmon.sh puts several of these together into a dashboard. It works in any terminal, and live in a graphics one:

examples/sysmon.sh                       # once
gfl view --watch examples/sysmon.sh      # live, repainting in place

--watch works in every terminal. Without graphics support it repaints the fallback text, which is still a live dashboard.

A script used with --watch does not need --force-osc: the watch loop sets GRACEFALL_FORCE_OSC=1 for it, because the script's own stdout is a pipe and the isatty rule would otherwise strip the envelopes it is being asked to produce.

As a library:

from gracefall import spark, meter, flow
print("p99  " + spark([92, 88, 84, 90, 97, 84], color="blue") + "  84ms")

The protocol in 30 seconds

ESC ] 4700 ; t=spark ; d=1,4,2,8 ; c=blue ST  ▁▄▂█  ESC ] 4700 ; ST

Open envelope with data, visible fallback, empty envelope to close. The span's cells are wherever the fallback lands, so there is no size negotiation and no capability query. Payloads are data, never pixels and never drawing commands, so the terminal owns rendering and can adapt it to theme, font size, and DPI. Full details, including the four design laws and the prior-art delta, are in SPEC.md.

Status

  • Emitter and CLI: working, v0.1
  • Reference renderer: working (SVG and PNG out)
  • gfl view, the kitty-graphics shim: working, verified in Ghostty and kitty
  • Terminals implementing OSC 4700 natively: none yet, and that is the honest state of a young protocol

If you maintain a terminal and want the first implementation, the renderer module is ~300 lines of executable semantics and the type set is six declarative primitives. Open an issue; the meter type alone is an afternoon.

Shell integration

shell/gracefall.zsh provides completions. Any zsh plugin manager can load it straight from this repo once published:

zinit light PouyanJay/gracefall

Changelog

CHANGELOG.md.

License

Code MIT. The specification text in SPEC.md is CC0 so implementations can copy it freely.

Metadata

Release files for gracefall 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gracefall 0.3.0
File Size Uploaded
gracefall-0.3.0.tar.gz 664.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gracefall 0.3.0
File Interpreter ABI Platform
gracefall-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 703.2 kB

Release files / gracefall-0.3.0.tar.gz

Download URL gracefall-0.3.0.tar.gz
Size 664.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6d3c9fa8450ee76d4a213f295c0d5f44c4deda36b1168837b09a651920001370
BLAKE2b-256 checksum
How to use checksums
dcd49e2760e2fee47be0943bbc25dbe1e75792c67c270c3d29ceb091518121ec
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / gracefall-0.3.0-py3-none-any.whl

Download URL gracefall-0.3.0-py3-none-any.whl
Size 39.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ece7682486e62e5cb1736149d9e36d495000794f4b6f7b3220b82d48ec92707d
BLAKE2b-256 checksum
How to use checksums
f547ef54a455270ce78190815fae3c50ef87b511e3e2911f3ac6b6adf9f0e33c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page