Selection-based mutable output buffer for LLM tools
Project description
editbuffer
editbuffer is a small Python runtime for editing an LLM's pending text output
before it is committed.
The public abstraction is selection-based editing, not file patches:
- select exact, contextual, fuzzy, block, or character-range targets;
- replace, insert before/after, or delete the selection;
- reject missing, ambiguous, invalid, and stale selections;
- inspect the current buffer and its audit history;
- commit the final artifact.
Install
pip install editbuffer
For local development:
python -m pip install -e .
Python 3.11+ is required. The core library has no runtime dependencies.
Quickstart
from editbuffer import EditBuffer, Selection
buf = EditBuffer()
buf.append('find . -name "*.py" -exec grep -n "TODO" {} ;')
buf.replace(Selection.exact("{} ;"), "{} \\;")
final = buf.commit()
Selections can also be dictionaries:
buf.replace(
{
"type": "context",
"before": 'grep -n "TODO" ',
"text": "{} ;",
"after": "",
},
"{} \\;",
)
LLM tool-call format
{
"op": "replace",
"target": {
"type": "context",
"before": "grep -n \"TODO\" ",
"text": "{} ;",
"after": ""
},
"text": "{} \\;"
}
Pass the decoded object to buffer.apply(operation). Supported operations are
append, replace, insert_before, insert_after, and delete.
Range selections use half-open character offsets and can reject stale edits:
{
"op": "delete",
"target": {
"type": "range",
"start": 10,
"end": 20,
"expected_version": 3
}
}
Failure behavior
- no match raises
TargetNotFoundError; - multiple matches raise
AmbiguousTargetErrorwith candidate ranges; occurrencecan explicitly choose a zero-based match;- invalid ranges or operations raise
InvalidOperationError; - a mismatched
expected_versionraisesStaleVersionError; - validator failures do not mutate text or history;
- fuzzy matching is opt-in and rejects low-confidence or competing candidates.
Fuzzy and block selections
Fuzzy selection uses the standard library and records the accepted confidence:
buf.replace(
Selection.fuzzy(
"run integrtion tests",
threshold=0.85,
ambiguity_margin=0.05,
),
"run unit tests",
)
It never runs as a fallback for exact/context selection. If no candidate meets
the threshold, or two candidates are too close, FuzzyMatchError includes
candidate ranges and scores.
Block selection requires an explicit ID. Fenced code blocks use:
```python editbuffer:id=setup
print("old")
```
Markdown regions use:
<!-- editbuffer:block summary -->
old content
<!-- /editbuffer:block -->
Selection.block("setup") selects the content inside the markers, preserving
the fence or comments. Duplicate IDs are rejected as ambiguous.
Snapshots and rollback
Every successful edit stores an in-memory snapshot:
buf.append("draft")
version = buf.version
buf.replace(Selection.exact("draft"), "final")
buf.rollback(version)
Rollback restores the snapshot as a new audited version. Snapshots live only
for the lifetime of the EditBuffer process.
Optional validators
from editbuffer import EditBuffer
from editbuffer.validators import valid_json, valid_shell
json_buffer = EditBuffer('{"ok": true}', validators=(valid_json,))
shell_buffer = EditBuffer("echo ok", validators=(valid_shell,))
valid_shell invokes the local POSIX sh -n parser without executing the
command.
CLI
The CLI stores an operation log in a JSON state file:
editbuffer new /tmp/output.json --text "hello world"
editbuffer replace /tmp/output.json '{"type":"exact","text":"world"}' "there"
editbuffer view /tmp/output.json
editbuffer history /tmp/output.json
editbuffer rollback /tmp/output.json 1
editbuffer commit /tmp/output.json
Use editbuffer apply STATE OPERATION_JSON for the complete operation schema.
MCP / agent integration
Install the optional server:
pipx install 'editbuffer[mcp]'
Or install with uvx without a persistent environment:
uvx --from 'editbuffer[mcp]' editbuffer-mcp
Connect it to Codex:
codex mcp add editbuffer -- editbuffer-mcp
Codex supports local STDIO MCP servers configured with codex mcp add; use
/mcp in the Codex terminal UI to confirm the server is active.
Claude Desktop and generic MCP client examples are in
docs/mcp.md.
The server exposes:
buffer_appendbuffer_listbuffer_viewbuffer_editbuffer_replacebuffer_insert_beforebuffer_insert_afterbuffer_deletebuffer_historybuffer_rollbackbuffer_committool_historytool_select
Buffers are in-memory and live for the MCP server process. The MCP layer calls the same core API and does not implement separate edit semantics.
Use the first-class selection tools for normal agent use:
{
"buffer_id": "answer",
"target": {"type": "exact", "text": "old"},
"text": "new"
}
buffer_edit remains available for raw JSON operations.
MCP calls are recorded in SQLite-backed history. tool_history returns recent
calls, newest first. tool_select creates a pending buffer from selectable
content in a previous call so the model can repair it instead of regenerating
it.
Examples
Scope
This project is not:
- an agent framework;
- a retrieval system or repo indexer;
- a full IDE;
- a replacement for coding agents;
- a generic output quality evaluator.
Persistent storage, atomic operation batches, TypeScript bindings, and syntax-aware block parsing are future work.
Development
PYTHONPATH=src python -m unittest discover -s tests -v
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file editbuffer-0.2.3.tar.gz.
File metadata
- Download URL: editbuffer-0.2.3.tar.gz
- Upload date:
- Size: 26.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0f250f4adbd3efab26c6eaf282f8419583476eba6a9e798277485c3b492dbcf
|
|
| MD5 |
3232ad682d72db85188d2c62b9eb92af
|
|
| BLAKE2b-256 |
396fad8de482ea64f6517cdc0febde0a8e5bfc304981e3e0b183cda6b6096a7e
|
File details
Details for the file editbuffer-0.2.3-py3-none-any.whl.
File metadata
- Download URL: editbuffer-0.2.3-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
314a351d5d608a947281f11370946108029de5042194791b73762726cb05ef5f
|
|
| MD5 |
c412338bf659e6f0b121f4ffefeaab29
|
|
| BLAKE2b-256 |
edda4554cabc6a1b9322d42d6662a37a9f47ceb22ad11a285a83043c3cfee114
|