- Scheme 90.7%
- C++ 3.6%
- C 2.9%
- Makefile 1.2%
- Shell 1.1%
- Other 0.5%
| .github/workflows | ||
| .jerboa | ||
| docs | ||
| scripts | ||
| src | ||
| support | ||
| tests | ||
| tools | ||
| .build.yml | ||
| .containerignore | ||
| .gitignore | ||
| .jerbuild | ||
| .jerbuild.freebsd-amd64 | ||
| .jerbuild.linux-amd64 | ||
| .jerbuild.linux-arm64 | ||
| .mcp.json | ||
| AGENTS.md | ||
| build-binary-qt.ss | ||
| build-binary.ss | ||
| CLAUDE.md | ||
| Containerfile | ||
| Containerfile.qt | ||
| Containerfile.tui | ||
| dependencies.lock | ||
| emacsclient.ss | ||
| jemacs-main.c | ||
| jemacs-qt-main.c | ||
| jemacs-ssh-agent-stub.c | ||
| jemacs-tls-stubs.c | ||
| jpkg.policy.sexp | ||
| jpkg.sexp | ||
| LICENSE | ||
| main.ss | ||
| Makefile | ||
| plan-android.md | ||
| plan.md | ||
| qt-main.ss | ||
| README.md | ||
| SECURITY.md | ||
| todo.md | ||
jerboa-emacs
A Chez Scheme port of the jerboa-based Emacs-like text editor, featuring a TUI (terminal) backend and a Qt graphical frontend.
Overview
jerboa-emacs is an Emacs-inspired editor built on top of:
- jerboa — Chez Scheme runtime with Gerbil-compatible stdlib
- jerboa-scintilla — Scintilla editor component FFI bindings
- jerboa-shell (jsh) — POSIX shell interpreter
- jerboa-qt — Qt 5/6 GUI bindings (Qt backend only)
The TUI backend runs in a terminal using Scintilla's text model. The Qt backend provides a full graphical interface.
Dependencies
Required (TUI backend)
| Dependency | Purpose | Location |
|---|---|---|
| Chez Scheme ≥ 9.6 | Scheme runtime | system |
| jerboa | Gerbil-compat stdlib | vendor/jerboa |
| jerboa-shell (jsh) | Shell interpreter | vendor/jerboa-shell |
| jerboa-sqlite | SQLite bindings used by jsh | vendor/jerboa-sqlite |
| jerboa-lsp | Optional Jerboa language server | vendor/jerboa-lsp |
| jerboa-scintilla | Scintilla editor FFI | vendor/jerboa-scintilla |
| jerboa-pcre2 | PCRE2 regex FFI | vendor/jerboa-pcre2 |
| PCRE2 development headers | Native regex library | system |
| libvterm development headers | Terminal emulation shim for make binary |
system |
On Debian/Ubuntu, install the native build prerequisites with:
sudo apt-get install build-essential pkg-config libpcre2-dev libvterm-dev
Additional (Qt backend)
| Dependency | Purpose | Location |
|---|---|---|
| Qt 5 or Qt 6 | GUI framework | system |
| QScintilla | Qt Scintilla widget | system |
| jerboa-qt | Qt FFI bindings | vendor/jerboa-qt |
Build
All commands run from the project root.
Jerboa build tools
make build and make binary build and use the vendored Jerboa multicall
toolchain at vendor/jerboa/dist/{jerboa,jerbuild}. The editor vendors and
builds its native Scheme/FFI dependencies under vendor/.
For systems that have the standalone Jerboa release toolchain but no full Jerboa runtime checkout, use:
make ensure-jerboa-tools
make build-jerbuild
make jerbuild-check
ensure-jerboa-tools follows the same convention as jerboa-code and
jerboa-shell: it prefers project-local tools, a sibling ../jerboa build, or
PATH, and otherwise downloads jerboa-${JERBOA_VERSION} into .jerboa/bin.
Downloaded toolchains are accepted only when their target-specific SHA-256
matches dependencies.lock; a checksum fetched beside the artifact is not a
trust root.
The .jerbuild* configs describe native target-host builds for macOS/Linux/
FreeBSD without requiring an installed full Jerboa runtime. Release targets use
the exact vendored jerbuild and statically link its pinned
libjerboa_native.a; failing crypto/TLS placeholder stubs are not part of
release binaries.
Cross and target builds
Linux and FreeBSD target artifacts are built with jerbuild on the target OS.
From macOS, the Linux amd64 target uses SSH by default:
make linux-amd64 # writes ./jemacs-linux-amd64
The default SSH host is linux.cons.io; override it with
LINUX_BUILD_HOST=host and LINUX_BUILD_ROOT=/path/to/jerboa-emacs.
Linux arm64 and FreeBSD follow the jerboa-shell pattern and are built on a
matching target host:
make linux-arm64 # on Linux arm64, or set LINUX_ARM64_BUILD_HOST
make freebsd-amd64 # writes ./jemacs-freebsd-amd64
Native target-host jerbuild configs are also available:
jerbuild build --config .jerbuild.linux-amd64
jerbuild build --config .jerbuild.linux-arm64
jerbuild build --config .jerbuild.freebsd-amd64
Vendor dependencies
make vendor-deps
This fetches the exact full commits recorded in dependencies.lock into
vendor/ and rejects an existing checkout at any other revision. Archive,
container, static OpenSSL 3.5.7 LTS, Chez, and Tree-sitter inputs are likewise
digest- or commit-pinned. The default make build target verifies this graph
first; make vendor-update never follows a mutable upstream head.
Build library modules
make build
This runs jerbuild to translate .ss Gerbil-syntax source files in src/ to Chez-compatible .sls library files in lib/. The build is incremental.
To force a full rebuild:
make rebuild
Build the jerboa-shell (jsh) library
The shell interpreter must be compiled separately:
cd vendor/jerboa-shell
make jsh-compile
Run (TUI mode)
make run
This builds and launches the terminal editor.
Run (Qt mode)
make run-qt
Requires the Qt backend build (see below).
Authenticated local control sockets
--repl PORT enables the full-power loopback debug REPL. It always requires a
fresh 256-bit token, atomically published with the port in the mode-0600
~/.jerboa-repl-port file. The always-on jerboa-client IPC endpoint uses an
independent token in ~/.jemacs-server. Both endpoints enforce bounded input,
deadlines, and one active connection. See
docs/repl-server.md for the protocol and threat model.
Build Qt backend
make build-qt
The Qt backend consists of 45 modules in src/jerboa-emacs/qt/ (~48,801 lines).
make build-qt simply runs the normal make build (which translates those
.ss modules to .sls alongside the rest of the editor) and then prints a
status banner — it does not compile a Qt binary by itself. To launch the Qt
frontend interpreted, use make run-qt; to produce a static jemacs-qt binary,
use make static-qt (below).
Static binaries (Podman / Linux host)
make static-qt # fully static jemacs-qt, built via Podman (Containerfile.qt)
make static-tui # static TUI binary, built on a prepared Linux host
static-qt routes to podman-static-qt, which builds with Podman and
copies the resulting jemacs-qt out of the image. The *-podman targets
(podman-deps, linux-static-qt-podman, linux-static-tui-podman, ...) use
the same PODMAN, PODMAN_PLATFORM, PODMAN_BUILD_FLAGS, and
PODMAN_RUN_FLAGS variables.
Testing
Run all standard tests
make test
The suite includes hostile authentication, overlong-frame, traversal, endpoint symlink, private-temp-file, and shell-metacharacter argv tests.
This runs: test-tier0, test-tier2, test-tier3, test-tier4, test-tier5, test-org, test-extra.
Run specific test suites
| Command | Description |
|---|---|
make test-functional |
Functional dispatch chain tests (250 tests) |
make test-term-hang |
Subprocess/blocking behavior diagnostic (13 tests) |
make test-tier0 |
Core data structures |
make test-tier2 |
Buffer and window primitives |
make test-tier3 |
Editor core operations |
make test-tier4 |
Shell integration |
make test-tier5 |
Full editor commands |
make test-org |
Org-mode subsystem |
Environment for tests
The Makefile sets these automatically:
LD_LIBRARY_PATH = vendor/jerboa-pcre2:vendor/jerboa-scintilla:vendor/jerboa-qt:vendor/jerboa-shell
JERBOA_SCINTILLA_LIB = vendor/jerboa-scintilla
JERBOA_PCRE2_LIB = vendor/jerboa-pcre2
Release Evidence
Local release candidates use:
make audit
make sbom
make reproducibility-report
make editor-flow-evidence
make release-evidence
make release-evidence writes dist/release-evidence/ with test, audit, SBOM,
reproducibility, target-host editor-flow status, build-environment, git-status,
release-input, and binary hash evidence. See docs/release-evidence.md for the
contents and remaining target-host review requirements.
Source Layout
src/
jerboa-emacs/
core.ss — App state, frame, window data types
buffer.ss — Buffer management
editor-core.ss — Core editor commands
editor.ss — Command registration
editor-cmds-a.ss — Commands A-M
editor-cmds-b.ss — Commands N-Z, git operations
editor-cmds-c.ss — Additional commands
shell.ss — Shell integration (jsh-based)
subprocess.ss — Non-blocking subprocess execution
terminal.ss — Terminal emulation
keymap.ss — Key binding system
helm.ss — Helm completion framework
persist.ss — Session persistence
editor-extra-*.ss — Extended features (org, AI, VCS, media, etc.)
qt/ — Qt graphical backend (45 modules)
lib/
jerboa-emacs/ — Generated .sls files (DO NOT EDIT)
tests/
test-functional.ss — Dispatch chain integration tests
test-term-hang.ss — Subprocess blocking diagnostic
test-tier*.ss — Tiered unit tests
test-org-*.ss — Org-mode tests
Architecture Notes
jerbuild code generation
.ss files in src/ use Gerbil-style syntax (def, defstruct, :module/path imports). The jerbuild tool (from jerboa) translates these to Chez Scheme .sls library files in lib/. Never edit .sls files directly — all changes go in .ss sources.
Qt backend and port ordering
Chez Scheme's open-process-ports returns values in this order:
(values write-stdin-port read-stdout-port read-stderr-port pid)
This differs from Gambit/Gerbil's open-process. All process I/O code uses this order.
Shell integration
The shell.ss module embeds the jsh POSIX shell interpreter. The subprocess.ss module provides run-process-interruptible for non-blocking subprocess execution with C-g interrupt support — this is the recommended path for long-running commands.
Note: gsh-capture / command-substitute in jsh uses open-output-file "/dev/fd/1" which acquires a Chez port registry lock. Running this in a secondary thread can deadlock with Chez's scheduler. Use run-process-interruptible for subprocess output capture in threaded contexts.
with-output-to-string
In Chez Scheme, with-output-to-string takes only a thunk:
(with-output-to-string (lambda () (display-exception e)))
The Gerbil form (with-output-to-string "" thunk) is not valid in Chez.
Key Variables (Makefile)
| Variable | Default | Description |
|---|---|---|
SCHEME |
vendor/jerboa/.chez/bin/scheme |
Chez Scheme executable |
JERBOA |
vendor/jerboa |
jerboa checkout |
JSH |
vendor/jerboa-shell/src |
jsh source path |
Override on the command line: make SCHEME=/usr/local/bin/chez build
Documentation
| Document | Description |
|---|---|
| docs/jemacs-vs-emacs.md | Feature comparison with GNU Emacs (48 categories, 2168+ commands) |
| docs/helm.md | Helm narrowing framework — architecture, matching engine, sources |
| docs/shell.md | Shell integration plan — jsh POSIX shell embedding |
| docs/repl-server.md | TCP debug REPL server for live introspection |
| docs/50-features.md | 50 features roadmap to close the gap with GNU Emacs |