No description
  • Scheme 71.1%
  • Shell 13.3%
  • C 11.2%
  • Makefile 4.1%
  • Common Lisp 0.3%
Find a file
2026-07-30 15:47:33 -06:00
.builds ci: set umask 022 in package/verify tasks too (jerbuild creates group-writable cache dirs during pkg operations) 2026-07-22 13:10:59 -06:00
.jerboa Security hardening and release readiness 2026-06-23 10:51:45 -06:00
docs fix(security): re-verify PID identity before kill to close TOCTOU (#29) 2026-07-21 18:13:55 -06:00
jtop perf(jtop): linear command-token join; cache downcased command for filter 2026-07-22 13:42:42 -06:00
scripts fix(security): re-verify PID identity before kill to close TOCTOU (#29) 2026-07-21 18:13:55 -06:00
support fix: close security audit findings 2026-07-11 17:25:50 -06:00
tests fix(security): re-verify PID identity before kill to close TOCTOU (#29) 2026-07-21 18:13:55 -06:00
vendor/termbox2 Initial commit: jtop cross-platform process monitor 2026-05-21 20:49:41 -06:00
.gitignore jpkg: complete binary package setup 2026-07-30 15:11:43 -06:00
.jerbuild fix: close security audit findings 2026-07-11 17:25:50 -06:00
AGENTS.md docs: remove jerboa-emacs restriction 2026-07-30 15:47:33 -06:00
jpkg.lock jpkg: complete binary package setup 2026-07-30 15:11:43 -06:00
jpkg.policy.sexp jpkg: complete binary package setup 2026-07-30 15:11:43 -06:00
jpkg.sexp jpkg: complete binary package setup 2026-07-30 15:11:43 -06:00
LICENSE Switch to MIT license 2026-07-21 13:42:20 -06:00
Makefile build: add lint target 2026-07-21 11:52:48 -06:00
README.md fix: close security audit findings 2026-07-11 17:25:50 -06:00
SECURITY.md fix: close security audit findings 2026-07-11 17:25:50 -06:00

jtop

A cross-platform terminal process monitor written in Jerboa. Inspired by top, atop, and mactop. Runs on Linux, FreeBSD, and macOS (including Apple Silicon).

Quick start

make run                          # build + run ./jtop-bin
make run ARGS='--once'            # single-frame snapshot (smoke test)
make run ARGS='--sort mem'        # sort processes by %MEM
make run ARGS='--with-power'      # macOS: sample powermetrics (needs sudo)

make binary                       # native binary -> ./jtop-bin
make test                         # import check + --once smoke test
make security                     # static release/security checks
make verify                       # security, native audit, and tests
make release-evidence             # dist/release-evidence bundle
make install                      # install ./jtop-bin to ~/.local/bin/jtop

Release evidence also records SBOM/provenance, repeated native binary reproducibility, and explicit live TUI smoke status.

Requires jerbuild, a C compiler, and ncurses. jerbuild bundles Chez Scheme and the Jerboa standard library; no Jerboa source checkout is required for a normal build. make auto-detects ../jerboa/dist/jerbuild when present, or uses jerbuild from PATH.

Binary

make binary produces ./jtop-bin, a native binary that bundles the Chez kernel, boot files, and termbox shim. It dynamically links the system ncurses library.

Keys (live mode)

Key Action
q quit
c / m / p sort by %CPU / %MEM / PID
+ / = / - faster / slower refresh
/ move selection
g / G jump to first / last process
space pause / resume (cache stays on screen)
/ start filter prompt (substring of cmd)
enter apply filter (empty clears)
esc cancel filter input
k kill selected process (y to confirm)
? / h toggle help screen

Display

 jtop  Apple M4 Pro  cores=14 (E:4 P:10)  up 8d 08:16  load 1.85 1.56 1.46
 CPU   7.3% [███████                                                     ]
 MEM  27.1% 13.0G/48.0G [█████████████████                               ]
 SWP  79.9%  4.0G/ 5.0G [████████████████████████████████████████        ]
 I/O  disk r:0K/s  w:0K/s   net in:12K/s  out:3K/s

      PID USER       *%CPU   %MEM RSS      S  TIME      COMMAND
      359 root         16.9    0.0    15.7M Ss 73:19.75  /usr/libexec/opendirectoryd
    39733 user         13.8    1.1   523.7M S+ 2:54.64   claude
    ...

The * marker before a column header indicates the active sort key.

Platform notes

Platform CPU% Per-core Memory Swap I/O rate GPU/Power
Linux /proc/stat yes yes yes yes
FreeBSD sysctl yes yes yes net only
macOS top -l aggregate vm_stat yes net only needs sudo

On macOS, per-core breakdown is suppressed (the data source processor_info() isn't available without C bindings; powermetrics requires sudo). Use --with-power to enable Apple-Silicon GPU% / power readouts via powermetrics -i 200 -n 1 (root).

Security and Privacy

jtop is network-free, but it displays local process details. Treat screenshots, logs, and --once output as sensitive because they can include users, PIDs, command names, resource counters, host model, and optional power telemetry.

Collectors never resolve through PATH or a shell. A native runner accepts only reviewed absolute, root-owned, non-group/world-writable executables, passes direct argv with a minimal clean environment, drains stdout/stderr concurrently, caps output, applies a monotonic deadline, and explicitly reaps every child. The k action invokes kill(2) directly after UI confirmation. --with-power is disabled by default because macOS powermetrics may require sudo.

Native boundaries are the termbox2 shim and the bounded process runner in jtop/tui-ffi.ss, jtop/jtop_tui_shim.c, jtop/process.ss, and jtop/jtop_process_runner.c. The production path is the native jerbuild binary, where all shim symbols are registered from generated C. Runtime shared-object loading is disabled. Plain/--once process fields escape C0/C1, ESC, line separators, backslash, and Unicode bidi controls before output.

Layout

jerboa-top/
├── Makefile
├── .jerbuild                  # native binary build definition
├── docs/                      # threat model and release evidence docs
├── scripts/security-check.sh  # release/security policy gate
├── support/import-check.ss    # import and FFI symbol smoke check
├── jtop/
│   ├── main.ss                # interpreter entry (sets library-directories)
│   ├── main-binary.ss         # static-binary entry (no dlopen, FFI via Sforeign_symbol)
│   ├── platform.ss            # OS detection + shared structs
│   ├── util.ss                # direct command + output-escaping utilities
│   ├── process.ss             # native runner FFI
│   ├── jtop_process_runner.c  # direct argv, clean env, caps/deadline/reaping
│   ├── collector.ss           # platform dispatcher
│   ├── collector-linux.ss     # /proc parsing
│   ├── collector-freebsd.ss   # sysctl + ps
│   ├── collector-macos.ss     # top/ps/vm_stat/sysctl + powermetrics
│   ├── history.ss             # ring-buffer sparkline histories
│   ├── tui-ffi.ss             # Chez FFI bindings for termbox2 (via shim)
│   ├── tui-widgets.ss         # bars, sparklines, columns, panels
│   ├── render.ss              # frame layout + ui-state struct
│   └── jtop_tui_shim.c        # C shim wrapping termbox2 for FFI
├── vendor/
│   └── termbox2/              # single-header TUI library (vendored)
└── README.md

TUI architecture

jtop uses termbox2 for input/output. A thin C shim (jtop_tui_shim.c) wraps the termbox API into plain functions that Chez can call via (foreign-procedure ...). The shim is linked into the native binary and registered with Sforeign_symbol from generated C main. (jtop tui-ffi) does not call load-shared-object; import-only and --once paths do not need an external TUI shared object.

--once skips termbox entirely and emits a plain-text snapshot — useful for scripts, smoke tests, and pipelines where there's no TTY.

The --once path proves collector/render startup only; production release still needs real TTY evidence on the target operating systems.