Tool

Give local LLMs gated control of your Emacs environment

El Yayster is a single-file Emacs package that lets a local LLM read your open buffers and act via gated Emacs Lisp, prompting before every mutation.

Works with emacsollamaopenaicurl

91
Spark score
out of 100
Updated 19 days ago
Source checked Sep 10, 2026
Version 1.0.0
Models
gpt 4oqwen 2 5

Add to Favorites

Why it matters

Turn Emacs into an agentic coding environment where a local LLM can perceive your live buffers, modes, and working directory, then act on them through gated Emacs Lisp-drafting code, running commands, and exploring documentation while you retain approval over every mutating action.

Outcomes

What it gets done

01

Read open buffers and current editor state to give the model situational awareness

02

Execute approved Emacs Lisp expressions and shell commands in your working directory

03

Explore Emacs documentation via apropos and describe for self-discovering capabilities

04

Stream non-blocking responses from any OpenAI-compatible endpoint with token tracking

Source

Get it from source

Spark does not host a copy of it.

Open source

Reports

Agent outcome reports

No reports yet

Overview

yayster.el

El Yayster is a single-file Emacs package that lets a local LLM agent perceive your open buffers, mode, and directory, then act inside your Emacs session via gated Emacs Lisp capabilities. Read-only actions auto-approve; mutating actions (eval elisp, write a buffer, run a shell command) always show the full command and prompt for approval before running. Use it when you want an agent that can act directly inside a running Emacs session against a local model, and you're willing to review and approve every mutating action it proposes.

What it does

El Yayster turns Emacs into a body a local LLM agent inhabits, rather than a chat buffer the model replies into: each turn it perceives your live environment (open buffers, current major mode, working directory) and acts on it through a gated set of Emacs Lisp capabilities - read_buffer, list_buffers, apropos, and describe are read-only and auto-approve by default; eval_elisp, write_buffer, and run_command are mutating and always prompt for permission (Allow / YOLO / Deny on a graphical frame, [y]/[n]/[!] in a terminal), showing the full, untruncated command or elisp that will run. It runs the ReAct loop (ACTION:/ARGS:/FINAL: text protocol, with a FINAL: line ending the turn and never executed even if quoted) against any OpenAI-compatible /chat/completions endpoint, with local Ollama as the default happy path and no cloud requirement; it has been tested with local models like Qwen and GLM with no code changes. Requests run in a non-blocking curl subprocess so Emacs stays responsive, streaming progress into a *yayster* buffer whose header line shows the live model, context-window occupancy (auto-detected from Ollama's /api/show), and per-turn/session token counts. It ships as a single self-contained file (yayster.el) with no ELPA package dependencies beyond cl-lib, json, subr-x, and the curl binary, plus an optional yayster-mode-line.el for a mode-line indicator that pulses while a turn is in flight.

To install:

(add-to-list 'load-path "/path/to/yayster.el")  ; the directory
(require 'yayster)
(yayster-awaken)

When to use - and when NOT to

Use it if you want an agent that can actually read your open buffers and act inside your running Emacs session - editing a buffer, evaluating elisp, running a shell command - rather than one confined to a separate chat window, and you're comfortable reviewing and approving every mutating action it proposes. It is deliberately v0 and small, meant to be read end to end and extended, not a polished production tool; YOLO mode (skip prompts for the rest of the session) is opt-in and session-scoped, never the default, and read-only tools auto-approve by default - meaning any open buffer, including one holding secrets, can be sent to the model without a prompt, which is a real footgun if you aren't paying attention to what's open. It is not suited to anyone who wants a fully sandboxed or hosted agent; a hosted API key is written to a mode-0600 temp file and passed to curl via -H @FILE so it never appears in ps, but the model itself still runs against whatever endpoint you configure.

Inputs and outputs

Input is a plain-English request via M-x yayster-step, run against the buffer and directory current at that moment. Output is the agent's FINAL: answer, echoed in the minibuffer and logged in the *yayster* buffer, plus any tool calls it made along the way (buffer reads, elisp evaluations, shell command output capped at yayster-command-max-bytes with a yayster-command-timeout-second limit, default 30s).

Integrations

Works against any OpenAI-compatible chat-completions endpoint - Ollama (localhost:11434) is the default, with yayster-hosts supporting switching between multiple configured endpoints via M-x yayster-use-host. Requires Emacs 28.1+ and the curl binary on PATH.

Who it's for

Emacs users who want a local, model-portable coding/editing agent that operates directly inside their live session with an explicit, readable permission gate on every mutating action - not people who want an unattended or fully autonomous agent. MIT licensed.

Source README

El Yayster

The Emacs. The Lisp. A wild little yes: give a local LLM the keys.

Most "LLM in Emacs" packages make Emacs a mouth that talks to a model: you type,
it replies into a buffer. El Yayster inverts that. It makes Emacs a body the
model inhabits - the agent perceives your live environment, and acts on it
through gated Emacs Lisp. Decide → call a tool → read the result → repeat, against
any OpenAI-compatible endpoint. Local Ollama is the happy path. No cloud required.

The name is the joke and the thesis. El is the definite article - the Yayster -
and it is also el, as in Emacs Lisp. The rest is the dare: a carefree, fun-loving
mindset, the kind that looks at eval and M-x and says yes, seat the model
there too
. The agent drafts; you still commit.

One self-contained file: yayster.el. No ELPA packages - cl-lib, json,
subr-x, the curl binary, and a reachable model.


Why it's different

  • Situated. Every turn, the agent is told what buffers you have open, your current
    mode, and your working directory. It knows it's in Emacs and speaks from inside it.
  • It acts, gated. Capabilities like eval_elisp, write_buffer, and run_command
    let the agent operate the editor - but every mutating action asks your permission
    first. The agent drafts; you commit.
  • Self-discovering. apropos and describe let it explore Emacs's own
    self-documentation. Its toolset grows from the editor itself.
  • Local-first & model-portable. Any OpenAI-compatible /chat/completions
    endpoint. Tested across local models (Qwen, GLM) with no code changes.
  • Non-blocking. Requests run in a curl subprocess; Emacs stays responsive.
    Progress streams into a *yayster* buffer.
  • Observable. The *yayster* header line shows the live model, context-window
    occupancy (auto-detected from Ollama's /api/show), and per-turn / session token
    counts.

Install

  1. Drop yayster.el somewhere on disk.

  2. Add to your init:

    (add-to-list 'load-path "/path/to/yayster.el")  ; the directory
    (require 'yayster)
    (yayster-awaken)
    
    ;; Optional: quick keys
    (global-set-key (kbd "C-c y") #'yayster-step)
    (global-set-key (kbd "C-c Y") #'yayster-use-host)
    
  3. Point it at your model (defaults to http://localhost:11434/v1/chat/completions):

    (setq yayster-endpoint "http://localhost:11434/v1/chat/completions"
          yayster-model    "qwen3:8b")
    

Requirements

  • Emacs 28.1+
  • curl on your PATH (built into macOS; apt install curl on Linux)
  • An OpenAI-compatible chat endpoint. Easiest is Ollama:
    ollama pull qwen3:8b then it serves on localhost:11434.

Use

  • M-x yayster-step (or C-c y) - ask in plain English.
    Watch *yayster*; the answer also echoes in the minibuffer.
    Tools run in the buffer and directory that were current when you issued the turn.
  • M-x yayster-use-host (or C-c Y) - switch between endpoints in yayster-hosts.
  • M-x yayster-abort - kill a hung turn, unlink temp files, clear the busy flag.

Optional: mode-line indicator

yayster-mode-line.el shows the current host, model, and a pulse while a turn
is in flight:

 ⌬ local qwen3:8b        (idle)
 ⌬ local qwen3:8b ◐      (a turn is running)
(require 'yayster-mode-line)   ;; installs itself into mode-line-format

It refreshes via advice on turn start/finish, host switch, abort, and safety
re-arm - no polling. Remove it with M-x yayster-mode-uninstall.

Try:

  • "What buffers do I have open?" → read-only, instant
  • "Count the functions matching org-agenda." → the agent discovers + calls apropos
  • "Give me a directory listing of my home dir, 5 most recent."run_command
    (you'll be asked to approve it)

Capabilities

Capability Mutating? What it does
read_buffer no Read a buffer's text
list_buffers no List buffers + major modes
apropos no Find functions matching a pattern (self-discovery)
describe no Read a function's docstring
eval_elisp yes Evaluate an Emacs Lisp expression
write_buffer yes Replace a buffer's contents
run_command yes Run a shell command

Read-only capabilities auto-approve (yayster-auto-approve-readonly, default on).
Mutating capabilities always prompt via yayster-confirm-function. The
prompt includes the capability name and the full argument payload - the
command or elisp that will run, no truncation - so a rebind to y-or-n-p is
not blind. The same text is shown in *yayster-permission*. On a graphical
frame: Allow, YOLO (stop asking for the rest of the session; re-arm with
M-x yayster-safety-on), and Deny. On a terminal: [y]/[n]/[!]. C-g /
cancel is deny.
run_command times out after yayster-command-timeout seconds (default 30) and
caps output at yayster-command-max-bytes.

The ReAct protocol: ACTION: / ARGS: must start their own lines; a FINAL: line
ends the turn and is never executed, even if an ACTION pair is also quoted. Malformed
JSON ARGS is not a tool call.

⚠️ Safety

Mutating tools (eval_elisp, write_buffer, run_command) always prompt
(Allow / Deny). The prompt shows the full command or elisp - no truncation.
Default install is that gate - read the payload before you Allow.

YOLO is opt-in and session-scoped until M-x yayster-safety-on. It is not
the default. Demo the package with prompts on.

Read-only tools (read_buffer, list_buffers) auto-approve and can still send
any open buffer (including secrets) to the model. That is the point, and also
the footgun. The gate only protects you if you read what you approve.

If you set yayster-api-key for a hosted API, the bearer token is written to
a mode-0600 temp file and passed to curl as -H @FILE. It never appears on ps.

How it works

Five small pieces, all in one file:

  1. Capabilities - a registry of gated Elisp functions (the agent's hands).
  2. Permission gate - read-only vs. mutating; mutating always asks.
  3. Situating prompt - live environment + a tool manifest.
  4. Agent loop - ReAct (ACTION: / ARGS: / FINAL:) against your endpoint.
  5. awaken - seats El Yayster at startup.

It's a v0 and deliberately small - easy to read end to end, easy to extend.

Tests

emacs -Q --batch -L . -l yayster.el -l test/yayster-tests.el \
  -f ert-run-tests-batch-and-exit

Roadmap

  • Native tool/function-calling (JSON-Schema tools) as an alternative to the ReAct text protocol
  • Token-level streaming into *yayster*
  • Automatic host failover
  • org-roam-backed memory (remember / recall as a knowledge graph)

FAQ

Common questions

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.