summary-ring-buffer
v0.1.0
Published
A zero-dependency, dual-runtime (Python and Node.js) ring buffer for compact conversation history with non-destructive eviction.
Readme
summary-ring-buffer
A zero-dependency, dual-runtime (Python and Node.js) ring buffer for compact conversation history with non-destructive eviction.
Tests: 216 passing (tests_passing: true) — 127 pytest + 89 node --test
Install
git clone <repo>
cd summary-ring-bufferPython requires no install (stdlib only). Node.js uses only built-in modules.
Quick start
Python
from scripts.ring_buffer import SummaryRingBuffer
buf = SummaryRingBuffer(capacity=5, max_summary_tokens=64)
buf.push("user", "Hello there")
buf.push("assistant", "Hi, how can I help?")
print(buf.render())Node.js
import { SummaryRingBuffer } from "./src/index.mjs";
const buf = new SummaryRingBuffer(5, 64);
buf.push("user", "Hello there");
buf.push("assistant", "Hi, how can I help?");
console.log(buf.render());CLI workflows
| Command | Description |
|---|---|
| init --capacity N --max-tokens M | Initialize a buffer with given capacity and max summary tokens. |
| push --role R --content C | Append a turn; auto-evict and summarize the oldest when full. |
| render | Render the current buffer as compact history. |
| tokens | Return token estimate for the current buffer. |
| evict-oldest | Force-evict the oldest turn (after manual summary). |
| config --summarizer MODEL --lang LANG | Set summarizer template. |
| export --file PATH | Persist buffer state to a JSON file. |
| import --file PATH | Restore buffer state from a JSON file. |
Mandatory Rules
Mandatory Rule 1
Zero-dep core. Only json and re from stdlib in Python; only built-in modules in Node.
Mandatory Rule 2
Token counting uses an optional peer helper (scripts/count_tokens.py, src/count_tokens.mjs) and is never imported by the core.
Mandatory Rule 3
Eviction is non-destructive. A summary is always produced before the turn is dropped.
Mandatory Rule 4
Buffer state is JSON-serializable via to_json / toJSON.
Mandatory Rule 5
Python and Node.js implementations are language-agnostic; same input sequence produces identical output.
Limitations
- Token counter is approximate. The core uses a word-whitespace approximation (
re.findall(r"\S+", ...)) for its own internal summaries. For exact token counts, use the optional peer helpers (scripts/count_tokens.py,src/count_tokens.mjs) which can wrap tiktoken or any tokenizer backend. - Role values are not type-validated.
push()accepts any role type (string, None, int, nested object) and preserves it verbatim. Render output is byte-identical between Python and Node only for primitive types (string, None/null, int, bool, list). For dict/object roles, output JSON whitespace may differ between runtimes; the storage layer is identical. - No concurrency guarantees. Both runtimes are single-threaded; concurrent
push()from multiple threads/processes is not safe. - Memory grows with content.
contentis freed only aftersummarize_turn()is called. Until then, full content lives inturns[].content.
Architecture
summary-ring-buffer/
├── package.json # Node runtime, zero deps
├── pyproject.toml # Python runtime, dependencies = []
├── plugin.json # Plugin manifest
├── hooks.json # Auto-summarize hook
├── scripts/
│ ├── ring_buffer.py # Python SummaryRingBuffer core
│ ├── count_tokens.py # Optional Python peer counter
│ └── summary_ring_buffer_cli.py # Python CLI entry
├── src/
│ ├── index.mjs # Node SummaryRingBuffer core
│ ├── count_tokens.mjs # Optional Node peer counter
│ ├── index.d.ts # TypeScript types
│ └── cli.mjs # Node CLI entry
├── skills/summary-ring-buffer/SKILL.md
├── rules/token-budget.md
├── tests/ # COVERAGE.md + parity + invariants + fuzz
└── benchmarks/bench_ring_buffer.pyLicense
MIT — see LICENSE.
