Bob's Emacs Mods — the other half
Read alice-emacs-mods first. That skill covers the host-level defaults: build (emacs-nox 30.2 from Nix), daemons (factory/server/claude-crdt/horsin-around), causal transients, org worlding, Gnus, keyboard, clipetty, takeover.bb. Bob covers everything else: the operational layer where live REPLs, cross-session coordination, and debug/recovery actually happen.
Ghostel mastery (the real one, not the comint imposter)
The imposter problem
(make-comint "ghostel: <name>" prog) yields a buffer named *ghostel: <name>* in comint-mode. This is not a ghostel buffer. It has no VT parsing, no OSC-133, no bridge, no TRAMP, no prompt-awareness. Many skills and my own earlier spawns emit comint imposters. Audit: (cl-remove-if-not (lambda (b) (and (string-match-p "ghostel" (buffer-name b)) (eq (with-current-buffer b major-mode) 'comint-mode))) (buffer-list)).
The correct spawn
(require 'ghostel)
(let ((ghostel-shell "/Users/alice/.juliaup/bin/julia")
(ghostel-buffer-name "*ghostel: julia-real*"))
(ghostel))
Buffer comes up in ghostel-mode, parses VT through ghostel-module.dylib (Zig, libghostty-vt). Everything downstream — strobe, prompt nav, bridge, OSC-52, TRAMP — starts working.
Parallel-spawn hazard
Spawning ≥2 ghostel buffers that each launch a heavy REPL (julia, stack ghci) in the same redisplay frame hangs the daemon. The Zig module's VT parser is not reentrant against concurrent PTY floods. Julia's startup banner alone is ~100 KB of escape sequences per pane. Three parallel spawns = instant hang (observed twice in the session).
Safe multi-spawn recipe
- Wrap shells with quiet flags via a trivial script.
~/bin/julia-quiet:#!/bin/sh exec /Users/alice/.juliaup/bin/julia --color=no --banner=no "$@" - Serialize spawns + poll for prompt between each:
(defun bob/ghostel-spawn-wait (name shell &optional timeout) (let ((ghostel-shell shell) (ghostel-buffer-name (format "*ghostel: %s*" name)) (deadline (+ (float-time) (or timeout 15)))) (unless (get-buffer ghostel-buffer-name) (ghostel)) (while (and (< (float-time) deadline) (not (with-current-buffer ghostel-buffer-name (save-excursion (goto-char (point-max)) (forward-line -1) (looking-at ".*\\(julia\\|> \\|λ>\\) *$"))))) (sit-for 0.2)) ghostel-buffer-name)) - Throttle during the multi-spawn window:
(let ((ghostel-timer-delay 0.1) (ghostel-immediate-redraw-threshold 4096) (ghostel-input-coalesce-delay 0.05)) (bob/ghostel-spawn-wait "sd-minus" "/Users/alice/bin/julia-quiet") (sit-for 2) (bob/ghostel-spawn-wait "sd-ergodic" "/Users/alice/bin/julia-quiet") (sit-for 2) (bob/ghostel-spawn-wait "sd-plus" "/Users/alice/bin/julia-quiet"))
Nuclear fallback — one daemon per tree
When the single-daemon pattern can't be made safe, fork per trit:
emacs --daemon=sd-minus -l ~/.claude/skills/emacs-strobe-walk/color-walk-gay.el
emacs --daemon=sd-ergodic -l ~/.claude/skills/emacs-strobe-walk/color-walk-gay.el
emacs --daemon=sd-plus -l ~/.claude/skills/emacs-strobe-walk/color-walk-gay.el
No shared VT parser. Cost: three frames. Win: true triadic parallelism, one GF(3) component per daemon. emacsclient -s sd-minus -t to attach.
Ghostel feature table (what alice doesn't cover)
| Feature | Knob | Value / notes |
|---|---|---|
| VT render rate | ghostel-timer-delay |
0.033 → 30 fps (lower for multi-spawn) |
| Adaptive FPS | ghostel-adaptive-fps |
t (idle buffers idle the timer) |
| Big-chunk bypass | ghostel-immediate-redraw-threshold |
256 chars default; raise to 4 KB during spawn |
| Input batching | ghostel-input-coalesce-delay |
3 ms default |
| Scrollback cap | ghostel-max-scrollback |
5 MB; raise to 64 MB for long-lived REPLs |
| Shell → Emacs bridge | ghostel-eval-cmds |
defaults: find-file, find-file-other-window, dired, dired-other-window, message |
| Prompt nav hooks | ghostel-command-{start,finish}-functions |
empty until shell sources etc/ghostel.{zsh,bash,fish} |
| SSH terminfo | ghostel-ssh-install-terminfo |
'auto |
| TRAMP shells | ghostel-tramp-shells |
per-host shell mapping |
| Compile mode | M-x ghostel-compile |
replacement for M-x compile, full VT |
| Eshell bridge | load ghostel-eshell |
eshell inside a ghostel buffer |
Extend the bridge for this session
(dolist (pair '(("gay-reseed" horsin/reseed)
("gay-strobe-on" horsin/enable)
("gay-strobe-off" horsin/disable)
("delta-append" (lambda (text) (append-to-file text nil "~/worlds/e/2026-04-21-delta.org")))))
(add-to-list 'ghostel-eval-cmds pair))
From any shell inside a ghostel buffer: printf '\e]51;e;gay-reseed;305419896\a' reseeds the strobe. No socket, no RPC, the VT stream is the control channel.
Known Emacs-daemon cracks (observed this session)
Crack 1: proof-easy-config: PG already in use or name/symbol mismatch
After (require 'proof-general), narya.el's own (proof-ready-for-assistant 'narya) fails the macro's name-check and define-derived-mode narya-mode never lands. Workaround: set narya-toolbar-entries to nil before loading (handles one error) and either load narya before any other PG assistant OR do (unload-feature 'proof-general t) first. Escape valve: use coq-mode + a .v file — PG bindings work fine there.
Crack 2: wrong-type-argument integerp (HI . LO) in horsin/tick
The strobe chain uses logand (+ seed golden) mask where seed can be a bignum. On Emacs 30.2 + aarch64, some path returns a (hi . lo) cons pair instead of a bignum integer, which logand can't handle. Observed every time horsin/seed exceeds fixnum range and the tick advances. Workaround: (setq horsin/seed (logand (or (and (consp horsin/seed) (logior (ash (car horsin/seed) 64) (cdr horsin/seed))) horsin/seed) #xFFFFFFFFFFFFFFFF)) as a coerce-on-read.
Crack 3: sequential narrow-terminal window splits silently drop panes
(dotimes (_ 4) (split-window-right)) on a 120-col terminal silently fails after ~3 splits — Emacs reports "Window too small for splitting" only when the fifth split is attempted directly, not inside dotimes. Always check (length (window-list)) after a split burst and fall back to vertical layout if short.
Crack 4: daemon hang on multi-ghostel spawn
Symptom: emacsclient -s server -e '(+ 1 2)' → SIGALRM after 3-5 s. Cause: see "Parallel-spawn hazard" above. Recovery: C-g in the user's live Emacs frame. No emacsclient-side recovery exists (all -e calls queue behind the hung VT parser).
Cross-session coordination (the L6 layer alice doesn't discuss)
The user routinely runs 4+ Claude Code sessions in parallel Ghostty tabs (⌘1–⌘4). These sessions share only:
/worlds/*filesystem~/.claude/skills/(shared skill library)~/.claude/projects/-Users-alice-worlds-*/memory/(per-project memory dirs)- the single Emacs daemon (PID 1831,
serversocket)
They do not share:
- conversation transcript (each session has its own
/tmp/claude-501/<uuid>/) - Monitor task outputs (same; each session's
tasks/*.outputis isolated) - a messaging inbox
Shared-state rendezvous patterns that work
- Memory entries under
~/.claude/projects/-Users-alice-worlds-e/memory/MEMORY.md— indexed, one-line hooks. Multiple sessions can read + append (last-writer-wins, but entries are append-only by convention). - DuckDB on disk —
/worlds/e/broadcast_e.duckdband/worlds/i/ies_beeper.duckdbare written by one session, queried by another. Tables likebarton_ies_messagesare durable rendezvous points. - Org buffers shared via the Emacs daemon — all sessions driving
serversee the same*ghostel: …*buffers. Two sessions editing the same buffer is safe as long as only one writes to a given region (CRDT is optional; last-writer-wins OK for ephemeral).
Anti-patterns observed
- Trying to SIGINT another session's Claude Code process → no cross-session permission.
- Polling
/tmp/claude-501/*/tasks/*.outputfor another session's progress → works but slow; use a DuckDB table instead.
REPL as dynamical citizen
Long-lived REPLs in ghostel buffers are not tools — they're citizens with state. Observed in this session:
*ghostel: nanoclj-zig*retained seed-split hex history across multiple parallel agents.*ghostel: julia-gay*retainedgay_seed!(0xd8dbb2df5c81869c)from one agent's earlier run.*ghostel: duckdb*onbroadcast_e.duckdbholds the result cache across queries.
Implication: source-verify before every REPL call (established in prior memory) AND state-verify — read the prompt history's tail, don't assume a fresh REPL. Pattern:
(defun bob/repl-tail (buf &optional n)
(with-current-buffer buf
(buffer-substring-no-properties
(max (point-min) (- (point-max) (or n 800)))
(point-max))))
Team-red canonical parameters (this session's gauge)
- minus seed:
0x144d8132a6e983f5(validator /-.tree) - ergodic seed:
0xa4dd4adf1c71e889(coordinator /0.tree) - plus seed:
0x4fd68f19a3c21491(generator /+.tree) - pleasant-red locus:
LCH(55.5, 139.9, 12.4)≈#f34240 - 3-MATCH triad: ghci (−1) ⊗ nanoclj-zig (0) ⊗ julia-gay (+1) = 0 ✓
Reseed the strobe:
(horsin/reseed #x144d8132a6e983f5)
(note crack 2 — coerce the seed first if it's a bignum cons).
The numeric horizons of the three REPL languages
| REPL | Native int | Max exact | Above that |
|---|---|---|---|
| GHCi | Word64 | 2^63−1 | bignum Integer |
| Julia | Int64 / UInt64 | 2^63−1 / 2^64−1 | BigInt on demand |
| nanoclj-zig | double (Int53) | 2^53−1 ≈ 9e15 | literal rejected: "invalid number" |
Implication for cross-REPL seeds: if the seed exceeds 2^53−1, split into 32-bit hi/lo halves and run paired SplitMix32. Reference code: /worlds/e/sm32-split.cljc. See memory repl_numeric_horizons_2026_04_22.md.
Canonical Gay.jl path
Four directories claim the name "Gay.jl" with TWO distinct UUIDs:
/worlds/g/Gay.jl— CANONICAL — UUIDf3dee6b2-1ce2-4cc9-bfb1-25e98f6f315b, v0.3.0 (newest, richest src tree)/worlds/g/Gay.jl_1— sibling copy, same HEAD/worlds/g/Gay.jl_2— older snapshot (v0.2.1)/worlds/e/exo__home1/exo/Gay.jl— DIFFERENT PACKAGE (UUIDa8c5b8e4…, v0.1.0) — do not load by accident
Global autoload already installed at ~/.julia/config/startup.jl; takes effect for every future Julia REPL via atreplinit. See memory canonical_gay_jl.md.
Layout patterns & their tradeoffs
| Grid | Use when | Gotchas |
|---|---|---|
| 1×3 horizontal | 3 REPLs, wide terminal | split-window-right ×2; narrow cols on small screens |
| 1×4 / 1×5 horizontal | 4–5 panes, wide | Window too small for splitting on < 160 col |
| 2×3 grid | 6 panes, balanced | need ≥ 120 col × 30 rows |
| 4×2 grid (tall) | 8 panes, narrow terminal | vertical-dominant; fall back if 2×4 horizontal fails |
| 3×1 vertical | 3 panes, narrow | each pane very short (7-8 rows) |
Always check (length (window-list)) after splits; fall back on failure.
QRTP distribution of a session
Full bundle template at /worlds/e/ghostty-emacs-combo/. Pack: scripts/pack.bb → frames/*.png. Play: scripts/play.sh at 8 fps. Receiver: scripts/unpack.sh via zbarcam. See README.org in that dir. ~228 KB bundle ≈ 395 frames ≈ 50 s / loop.
bb-native MCP server template
When a skill wants an MCP server without Node/TypeScript, use /worlds/e/bb-mcp.bb (95 lines, pure babashka). Replaces a 40-file TypeScript babashka-mcp-server. Register in ~/.mcp.json with stdio transport.
Debug harness
Proposed but not yet scaffolded (TODO):
debug/scan-sessions.sh— inventory all/tmp/claude-501/*/tasks/+ last 5 outputsdebug/emacs-health.el—M-x bob/healthprints daemon-PID, seed, tick, layout, messages-taildebug/shared-inbox/—fswatch-triggered cross-session messagingdebug/pg-snapshot.el— dump PG locked/processing offsets per.vbuffer
Things NOT to do (session-observed)
- Don't
(julia-snail)on a fresh project without killing PG state first —proof-easy-configcollides with narya.el's init (see Crack 1). - Don't spawn ≥2 ghostel buffers in the same redisplay frame unless banner-silenced AND throttled.
- Don't call
vterm-send-string— we're in comint/ghostel land. Useprocess-send-string (get-buffer-process BUF) STR. - Don't assume a ghostel-prefixed buffer is in ghostel-mode. Grep
major-modefirst. - Don't use fish-shell
forloops in Monitor scripts — they don't word-split$VAR. Usebash -c '…'explicitly OR inline values. - Don't
Pkg.addin a ghostel pane before the prompt is visible — the resolver progress flood blocks the VT parser. - Don't assume the Emacs "daemon" is a daemon — on this machine it's
emacs -nw(PID 1831) running interactively in a TTY that happens to host theserversocket.C-gat the user's frame is the canonical recovery.
Quick triage
| Symptom | Probe | Fix |
|---|---|---|
emacsclient -s server -e '(+ 1 2)' → SIGALRM |
daemon hung | user C-g |
*ghostel:…* in comint-mode |
comint imposter | kill + respawn with (ghostel) |
horsin tick error (HI . LO) |
seed overflow to cons | coerce with mask |
| narya-mode doesn't activate | PG macro collision | setq narya-toolbar-entries, then unload-feature 'proof-general |
| REPL pane tripled | narrow-terminal split collapse | fall back to vertical layout |
| shell commands in ghostel don't trigger OSC-133 | shell rc hasn't sourced etc/ghostel.zsh |
source it |
Session-specific memory hooks
memory/delta_2026_04_21.md— team-red ladder + 3-MATCH triad + source-verify discipline + open-games verdictmemory/repl_numeric_horizons_2026_04_22.md— three REPLs, three ints, canonicalmemory/canonical_gay_jl.md— Gay.jl path disambiguation (f3dee6b2 = canonical)memory/team_red_locus.md— LCH(55, 138, 12) locus, #f34240- canonical Beeper archive:
/Users/alice/Library/Application Support/BeeperTexts/account.db(352 MB) +/worlds/i/ies_beeper.duckdb(478 MB, pre-processed IES slice)
GF(3) triadic composition
alice-emacs-mods (-1) ⊗ bob-emacs-mods (0) ⊗ plurigrid-asi-ghostel (+1) = 0 ✓
Alice anchors the host (validator of the install). Bob coordinates the live operation (ergodic). Plurigrid-asi-ghostel generates the substrate for new REPL/agent channels. The three together tile the Emacs-mod space.
See also (bidirectional)
- [[alice-emacs-mods]] — host-level defaults; read first
- [[plurigrid-asi-ghostel]] — ghostel substrate for agent channels
- [[ghostel]] — the underlying terminal
- [[emacs-strobe-walk]] — horsin/color-walk; target of the bignum coerce workaround
- [[proofgeneral-narya]] — Narya PG integration; source of Crack 1
- [[three-match]] — the 3-MATCH triadic framework we instantiate on REPLs
- [[emacs-color-chain]] — sibling strobe skill
- [[julia-gay]] / [[clojure]] — language content layers
- [[bumpus-narratives]] / [[open-games]] — proof-target formalizations with open cracks
Session cross-refs (2026-04-23, e-session)
This skill participates in the 32-skill working set assembled in /Users/alice/worlds/e session 2026-04-23 (15 new skills also created).
Outgoing references (this skill src → other skill dest):
bob-emacs-mods→plurigrid-asi-ghostel— VT substrate (named ghostel-vt in ghostel-rooms)bob-emacs-mods→three-match— 3-MATCH framework bob's session instantiatesbob-emacs-mods→bumpus-narratives— proof-target sheaf substratebob-emacs-mods→open-games— proof-target formalization with open cracksbob-emacs-mods→emacs-strobe-walk— target of bignum-safe patchbob-emacs-mods→proofgeneral-narya— Crack #1 source skillbob-emacs-mods→ies-triadic— 3-MATCH triad instantiated in ghci/nanoclj/julia-gaybob-emacs-mods→horsin-bignum-safe— implements the Crack #2 workaround bob documentsbob-emacs-mods→ghostel-imposter-audit— implements the imposter audit bob requestsbob-emacs-mods→ghostel-multi-spawn-safe— implements bob's safe-multi-spawn recipebob-emacs-mods→three-repl-triad— codifies bob's canonical team-red triad seeds
Incoming references (other skill src → this skill dest):
alice-emacs-mods→bob-emacs-mods— operational complement to alice host-levelplurigrid-asi-ghostel→bob-emacs-mods— ghostel mastery and multi-daemon orchestration
Verified GF(3) triads containing this skill:
- alice-emacs-mods (-1) ⊗ bob-emacs-mods (0) ⊗ plurigrid-asi-ghostel (+1) = 0 ✓
REPL atlas
Part of: repl-commons. Family canonical: emacs.