# Pmacs

Parallel Emacs --- a Rust-cored, Lua-scripted editor in the Emacs tradition.

Pmacs runs the editor's hot path (rope, buffers, views, async runtime,
process supervision) in Rust, and exposes the rest --- commands, keymaps,
hooks, packages --- through an embedded Lua VM. The design follows Emacs
in shape (configurable, introspectable, programmable from inside) but
discards the single-threaded substrate; workers, message bus, and a
coroutine-based async surface are core primitives, not bolt-ons.

The editor is partitioned into a long-lived **instance** (the daemon
that owns buffers, processes, and language services) and thin
**frontends** that attach over a typed protocol (currently v20). Two
frontends ship today:

- a **TUI** (crossterm cell grid), attachable locally over a Unix
  socket or remotely over SSH, with reconnect-on-drop modeled on
  `mosh`; and
- **pmacs-gpu**, a GPU frontend (wgpu + winit + glyphon) that renders
  from a *semantic projection* of editor state --- style spans,
  decorations, inlay adornments --- rather than a character grid, and
  edits optimistically against a local CRDT replica for
  latency-free typing.

Buffers are optionally CRDT-backed (`loro`, behind `--features crdt`),
so multiple frontends --- TUI and GPU, local and remote --- can edit
the same buffers concurrently with live cursor/selection presence.

## Status

**v1.1.0 --- stable core, active development, and the first release
with prebuilt binaries.** The v1.0 gate (the instance/frontend
partition, the Lua surface, and a REPL package audited to use zero
direct Rust core access) shipped some time ago. Development since has
expanded the semantic frontend protocol from v6 through **v21**, brought
the GPU frontend near input/render parity with the TUI, and completed
the LSP, editing, persistence, themes, and terminal arcs. Recent work
added major modes and modeline detection, a typed configuration
registry, composable statuslines, multi-language syntax processing,
cross-frontend tab-width parity, a directory browser, a describe/list
command family, and a bottom panel on both frontends.

Current direction lives in `COHERENCE.md` (the product-coherence thesis
and its audited priority order) and `docs/agent-handoff.md` (durable
project state). `docs/roadmap-2026-07.md` is a historical planning
snapshot and is no longer the authority.

Public contributions are open: use, evaluate, file issues, and send
pull requests.

## Highlights

**Editing & UI.** CUA-style region editing plus Emacs kill/yank and kill-ring
bindings; linear undo/redo; query-replace; incremental substring and regex
search (`C-s` / `C-r` / `C-M-s`); comment, auto-indent, auto-pair, transpose,
case, line, and region operations; line-number gutter with absolute, relative,
and hybrid modes; diagnostic signs; context menu; OS clipboard integration
(OSC 52 in the TUI, native in the GPU); minibuffer completion with persisted
history; buffer-list and compilation modes; self-navigable help. Named `ui.*`
theme faces, live GPU font selection, and composable per-window statusline
providers keep chrome and modelines runtime-configurable. Saves are atomic
(temp + rename + parent fsync, mode-preserving).

**Language intelligence.** The async LSP client provides diagnostics,
rename with `prepareRename`, cross-file definitions, hover, signature help,
references, document symbols, code actions, formatting, semantic tokens, and
inline inlay hints. Preconfigured servers cover Rust, C/C++, Python, Go,
JavaScript/TypeScript, Lua, Bash, TOML, Zig, Dockerfile, CMake, JSON, and YAML.
Bundled tree-sitter grammars include those languages plus Markdown, Make, and
CUDA; nested Markdown fences and frontmatter use multi-language injections,
and locals-query processing distinguishes shadowed builtins. Bounded Emacs
and Vim modelines join extensions, exact filenames, and shebangs in one
fresh-load language decision. That decision initializes the buffer's major
mode, drives syntax/LSP/pairing/comment behavior, and enables mode-scoped
keymaps. A persistent project-symbol index (`.pmacs/index.json`) rides the
same worker infrastructure.

**Collaboration & frontends.** With `--features crdt`, buffers are CRDT-backed
and any number of frontends attach to one daemon and edit concurrently; peers
see each other's cursors and selections as translucent washes. The TUI and GPU
frontends both host owned full-screen terminal sessions; protocol-v19 terminal
frames preserve the fixed-cell VT screen while each frontend owns its
scroll/selection/input context. The GPU frontend also provides a live minimap,
wavy diagnostic squiggles, a status band, and optimistic local editing that
rebases in-flight edits through authoritative frames. Buffer text, syntax,
diagnostics, carets, hits, and minimap geometry now share one eight-column tab
projection without mutating source bytes.

**Extensibility.** The `pmacs.*` Lua namespaces cover buffers, windows,
commands, global/mode/buffer keymaps, hooks, themes, statusline providers,
tree-sitter, LSP stores, async workers, and a PTY-aware process supervisor.
The typed, introspectable `pmacs.config` registry supports global and
buffer-local values, listeners, startup-only settings, and `describe-setting`.
A package manager installs from git (`github:owner/repo`,
version/branch/commit pins) with transitive dependency resolution and a
SHA-256 lockfile. Pmacs is also an **MCP client**: packages can spawn MCP
servers and consume their tools, resources, and prompts --- AI integrations
are packages over a transport, not a built-in feature. The bundled REPL
package is written entirely against the public Lua API.

## Running

Single-process TUI:

```sh
pmacs [FILE]                 # TUI; -nw reserved for when a GUI default lands
```

GPU frontend (one command; the root binary starts or reuses the daemon):

```sh
pmacs --gpu                         # default instance; no initial file
pmacs --gpu README.md               # default instance; open one file
pmacs --gpu --socket NAME FILE      # named instance; bare NAME →
                                    #   <runtime>/pmacs/NAME.sock
pmacs --gpu -- --leading-dash       # `--` ends option parsing
```

`pmacs --gpu` requires the root `pmacs` binary to be built with the
`crdt` feature. It discovers a sibling `pmacs-gpu` binary first, then
falls back to `pmacs-gpu` on `PATH`. When `FILE` is present, the daemon
loads or creates it and completes startup hooks before the GPU window
appears. Closing the window detaches only that frontend; the daemon
remains available for later GPU or TUI attaches.

Daemon + attached TUI frontends:

```sh
pmacs --daemon --socket NAME        # foreground daemon
pmacs --attach --socket NAME        # TUI frontend; F12 detaches
pmacs --attach user@host            # remote TUI over SSH
```

For debugging an already-running daemon, the low-level GPU command stays
available and never auto-starts or replaces anything:

```sh
pmacs-gpu --attach /absolute/path/to/pmacs.sock
```

`pmacs --attach` also understands `ssh:user@host/instance`,
`local:/path.sock`, and bare hostnames (treated as SSH). See
`pmacs --help` for the full matrix.

User configuration is plain Lua at
`$XDG_CONFIG_HOME/pmacs/init.lua` (default `~/.config/pmacs/init.lua`),
loaded after the builtin runtime so plain assignments override
defaults --- keybindings, `pmacs.lsp.config`, theme overrides, and
package installs all live there.

## Install

Download an archive from the
[releases page](https://github.com/levineuwirth/pmacs/releases), unpack
it, and put both binaries somewhere on your `PATH`.

**Keep `pmacs` and `pmacs-gpu` together.** `pmacs --gpu` looks for
`pmacs-gpu` beside itself first and only then falls back to a `PATH`
lookup, so an unpacked release is self-contained as long as the two
stay in the same directory.

Verify a download:

```sh
sha256sum -c SHA256SUMS --ignore-missing
```

| platform | built on | notes |
|---|---|---|
| Linux x86_64 | Ubuntu 22.04 | requires **glibc ≥ 2.35** — Ubuntu 22.04+, Debian 12+. **RHEL 9 (glibc 2.34) is not supported yet.** |
| macOS arm64 | macOS 15 | Apple Silicon only; Intel is not built yet. Binaries are **unsigned and not notarized**, so Gatekeeper will quarantine them until you allow them explicitly. |

Releases carry binaries only — there is no in-place update, rollback, or
package-manager distribution yet. Build from source for any platform not
listed, and see "Runtime dependencies" below for what the editor assumes
is present.

## Build

Builds on the toolchain pinned in `rust-toolchain.toml` (Rust
`1.95.0`, edition 2024); rustup selects it automatically.

```sh
# Coherent root + GPU release build. The package-qualified feature keeps
# the separate pmacs-gpu package feature-free while enabling CRDT in pmacs.
cargo build --release --workspace --features pmacs/crdt

target/release/pmacs --gpu README.md # one-command managed GPU file launch
cargo run --release -- --version     # default-run selects the pmacs binary
cargo test --workspace              # unit + integration tests (all crates)
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings   # incl. pmacs-gpu
```

### Feature matrix

Cargo features fall into two independent axes. **Do not use
`--all-features`** — it enables both Lua flavors at once, which cannot
build (see below).

| Feature  | Axis       | Notes                                                       |
| -------- | ---------- | ---------------------------------------------------------- |
| `luajit` | Lua flavor | **Default.** LuaJIT backend via `mlua` (vendored).         |
| `lua54`  | Lua flavor | Lua 5.4 fallback for hosts without LuaJIT (big-endian, …). |
| `crdt`   | Buffer     | Opt-in CRDT-backed buffer mode (adds the `loro` dep). v1.0 builds enable it; orthogonal to the flavor. |

**Exactly one Lua flavor must be enabled** — `luajit` *or* `lua54`, never
both (and never neither). They map to `mlua`'s mutually-exclusive Lua
backends, so `--all-features` (or `--features luajit,lua54`, or
`--no-default-features` with no flavor) fails in the `mlua-sys` build
script with *"You can enable only one of the features: …"*. That check
lives in a dependency cargo builds first, so pmacs can't replace it with a
friendlier error — the fix is to build a specific flavor. Supported build
lines:

```sh
cargo build --release                                   # luajit (default)
cargo build --release --no-default-features --features lua54
cargo build --release --features crdt                   # luajit + crdt
cargo build --release --no-default-features --features lua54,crdt
```

CI, `cargo hack`, and distro tooling should iterate the flavors
explicitly (`--no-default-features --features <flavor>[,crdt]`) rather
than reaching for `--all-features`. Both flavors pass the full test suite;
CI runs the matrix on every push.

Release-only perf gates (M5 keystroke-to-render, M6 ingest/RSS/cancel
and scrollback navigation/search) are `#[ignore]`'d during normal
test runs and exercised in CI under dedicated jobs. The GPU frontend
has headless render tests (offscreen wgpu, pixels read back) that run
in CI under lavapipe and skip gracefully on machines without a Vulkan
adapter (`PMACS_REQUIRE_GPU=1` turns a missing adapter into a hard
failure).

## Runtime requirements

The pmacs binary depends on a small set of POSIX command-line tools
at runtime. The dependency exists because the project enforces
`#![forbid(unsafe_code)]` everywhere, including in tests; calls that
would otherwise need `unsafe` (PTY raw-mode setup, signal name
translation) are routed through trampolines that exec these tools.

- **`/bin/sh`** (POSIX shell). Used for the PTY raw-mode trampoline:
  `/bin/sh -c 'stty raw -echo </dev/tty 2>/dev/null; exec "$@"' --`
  configures the controlling TTY's line discipline before exec'ing
  the actual subprocess. Required by the REPL package and any other
  caller that spawns a process in raw PTY mode.
- **`stty`** (coreutils). The line-discipline configurator invoked
  by the trampoline above.
- **`coreutils`** more broadly. The M6 process-supervisor tests
  spawn `cat`, `yes`, and `which`; absent these the test suite (not
  the editor itself) degrades. `which` is also used by the M6.5
  shell-locator helper to find `bash` / `zsh` / `fish` for
  per-shell integration tests. The M7.2 fetcher's timeout test
  uses `sleep`.
- **`setsid`** (util-linux, Linux only, **optional**). The process
  teardown-deadlock test uses `setsid --fork` to orphan a grandchild,
  which is the only way to reproduce that deadlock without depending on
  shell `&` semantics (they differ between `bash` and `dash`). The test
  **skips** when `setsid` is absent, so a minimal or BusyBox environment
  still runs `cargo test --lib`; set `PMACS_REQUIRE_SETSID=1` to make
  that skip a failure, as CI does on Linux.
- **`/bin/bash`** (**optional**, Linux only). The signal diagnostic's
  job-control corroboration test needs a terminal whose foreground
  process group is not the spawned leader, which `bash -m` produces by
  running a foreground job in its own process group. The path matters:
  the test spawns `/bin/bash` directly rather than resolving `bash` on
  `PATH`, and skips when that path is absent. Set `PMACS_REQUIRE_BASH=1`
  to make the skip a failure, as CI does on Linux.

  **It is deliberately not armed on macOS**, which ships bash 3.2 but
  where a non-interactive `bash -m` was measured in CI to keep the
  terminal on the leader — so the divergence the test needs never
  happens there. The divergent case is pinned on every platform by
  injecting the foreground group instead.
- **`git`** (added in M7.2). Required for any package operation:
  the package fetcher shells out to `git` to clone, fetch, and
  resolve refs, with a deterministic environment
  (`GIT_TERMINAL_PROMPT=0`, `GIT_CONFIG_NOSYSTEM=1`, `LC_ALL=C`,
  inherited `GIT_*` variables stripped). Authentication for
  private repositories rides the user's existing git configuration
  (credential helpers, SSH agent), so packagers do not need a
  separate auth story. Pre-M7 builds without package operations
  do not need git.
- **`tar`** (added in M7.3). Required for `pmacs.packages.install`:
  the installer materializes a snapshot via `git archive --format=tar`
  piped into `tar -x -C <dest>`, which keeps the on-disk install
  directory self-contained (no `.git` linkage back to the bare
  cache, no working-tree state). GNU tar and bsdtar both work.
  Pre-M7 builds and any path that doesn't call
  `pmacs.packages.install{...}` do not need tar.

Distribution packagers should ensure these are runtime dependencies
of the pmacs package. On a typical Linux distribution, busybox or
GNU coreutils plus a shell of any kind satisfies the requirement; on
macOS the system shell and `/usr/bin/stty` are both standard.

The Lua VM (LuaJIT or Lua 5.4) is statically vendored via `mlua`'s
`vendored` feature, so there is no external Lua dependency at
runtime.

The GPU frontend additionally needs a Vulkan-capable driver stack
(any real GPU driver, or lavapipe for software rendering); its font
(JetBrains Mono, OFL-licensed) is bundled into the binary.

## Layout

The workspace has three first-party crates:

```
src/                 pmacs — the core + TUI + daemon
  rope.rs              persistent byte-sequence backing every buffer
  buffer.rs            buffer + view chain + undo/redo
  editor_core.rs       cursor + commands + edit dispatch
  crdt.rs              loro-backed CRDT buffer state (feature `crdt`)
  daemon.rs            instance side of the frontend partition
  attach.rs            frontend side; transports + reconnect
  semantic_render.rs   semantic-frame producer (StyleSpans, Decorations, …)
  lsp.rs               language-server client
  diag.rs, highlight.rs  diagnostic + syntax/semantic-token rendering
  syntax.rs            tree-sitter integration
  search.rs            incremental search (substring + regex)
  minibuffer.rs        prompt, completion, persisted history
  menu.rs              context-menu model
  file_io.rs           atomic saves + external-modification detection
  async_runtime.rs     worker pool + message bus
  process.rs           PTY-aware process supervisor
  ansi.rs              ECMA-48 parser
  project.rs, project_index.rs  project detection + symbol index
  packages/            resolver, fetcher, installer, lockfile, loader
  mcp.rs               MCP client (packages speak to MCP servers)
  lua_bindings/        pmacs.* Lua surface installers
  text_view.rs         cell-grid renderer
  frontend.rs          crossterm TUI
  main.rs              entry point (TUI / daemon / attach modes)

pmacs-protocol/      wire types + framing codec shared by all frontends
pmacs-gpu/           the GPU frontend (wgpu + winit + glyphon)

builtin/             Lua runtime shipped with the binary
  commands/default.lua  named commands for every editor primitive
  keymaps/default.lua   default key bindings
  hooks/default.lua     built-in hook definitions
  menus/default.lua     context-menu items
  runtime/              async, lsp, syntax, mcp, fs runtimes
  packages/repl/        the bundled REPL package

docs/                design notes, framing docs, and the roadmap
tests/               integration tests (acceptance gates per milestone)
```

## License

Dual-licensed under either of:

- MIT License ([LICENSE-MIT](LICENSE-MIT))
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))

at your option.
