The application owns the language.
REPLAI owns the line.
An embeddable terminal interaction engine for Rust and C.
Parsing, command semantics, execution, persistence and scheduling remain host-owned.
Quick Start · Choose a mode · Capabilities · Architecture · Support · Performance · Docs
REPLAI provides Unicode editing, revision-safe host analysis, rich completion, validated multiline interaction, structured presentation and explicit terminal lifecycle management. It occupies a useful middle layer: the host can begin with a small line read, then adopt session or driven control without moving its language or event loop into a terminal framework.
- Rust: Blocking · Session · Driven. C/C++: ABI 1 session.
- Runtime: Linux GNU x86_64/ARM64 · macOS ARM64. Portable core: Windows x86_64.
- Ownership: the host keeps parsing, semantics, execution, persistence and scheduling; REPLAI owns editing, terminal lifecycle, revision provenance and generic presentation.
- License: MIT.
Real PTY, public APIs, deterministic local fixture. The host supplies operation names, analysis and validation; REPLAI preserves the draft, cursor and completion selection while host output arrives.
Watch the 11.63-second interaction
The animation comes from the same executable and real PTY. It is illustrative; it is not benchmark evidence. The static image above contains the essential information without motion. Capture and asset provenance.
The same public surface can support a data-oriented console or render structured output without an active editor. Both captures below come from deterministic local fixtures; neither contacts a database or build service.
An interactive query console: host-owned commands and records, REPLAI-owned editing, results layout and draft restoration.
A standalone Document: headings, facts, status, tabular data and help rendered
without raw ANSI. Reproduce the focused captures.
On Linux or macOS, with Git and a current stable Rust toolchain:
git clone https://github.com/mothx9/replai.git
cd replai
cargo run --locked --example showcaseTry de, Tab, Tab, then wait for the host notice. Enter accepts the selected
candidate; another Enter validates and submits. Type deploy {, press Enter,
Tab-indent service café, close with } and press Enter. Up recalls the exact
multiline entry. Ctrl-D on an empty draft exits.
The showcase executes no command and contacts no service. Its fixture owns all
operation meanings. If cargo is missing, install Rust with
rustup first. More paths are mapped in
use-case recipes.
| Your application | REPLAI mode | Host responsibility | Typical fit | Start here |
|---|---|---|---|---|
| Read → execute → read | Blocking | Execute each submitted line | Deterministic CLI, turn-by-turn chat | simple.rs · contract |
| Rich interactive console | Session | Poll and handle events/results | Database, debugger, admin console | showcase.rs · contract |
| Existing event loop | Driven | Reactor, readiness and scheduling | Network client, debugger, model frontend | driven.rs · contract |
| C/C++ process | C ABI 1 session | Semantics and polling loop | Native tools and existing C systems | demo.c · contract |
Blocking keeps the smallest host small. Session exposes the interaction event boundary. Driven lets an existing reactor wait on terminal readiness, REPLAI deadlines and application events. None of these modes gives REPLAI ownership of application threads, signals or command execution.
The matrix makes the intentional Rust/C asymmetry explicit. “Replacement only” means ABI 1 can apply a host-selected synchronous replacement but has no candidate set/menu contract.
| Capability | Rust | C ABI 1 | Host-owned part |
|---|---|---|---|
| Unicode/grapheme editing | 🟢 Qualified | 🟢 Qualified | Accepted input policy |
| History navigation / reverse search | 🟢 Provider + bounded search | 🟡 Navigation only | Persistence, retention and privacy |
| Word editing / undo / kill-yank | 🟢 Qualified + configurable | 🟡 Fixed bindings only | Mapping policy |
| Rich completion UI / helpers | 🟢 Qualified + paged | 🟡 Replacement only | Context and semantic ranking |
| Revision-safe autosuggestion | 🟢 Qualified suffix insertion | 🔴 Outside ABI 1 | Source choice and scheduling |
| Revision snapshots / stale refusal | 🟢 Qualified | 🔴 Outside ABI 1 | Analysis meaning and schedule |
| Validated multiline | 🟢 Qualified | 🔴 Outside ABI 1 | Grammar and diagnostics |
| Host spans / non-canonical hints | 🟢 Qualified | 🔴 Outside ABI 1 | Classification and hint text |
| Structured documents | 🟢 Qualified | 🔴 Outside ABI 1 | Semantic content |
| Coordinated output | 🟢 Plain + documents | 🟡 Plain text only | Output meaning and serialization |
| Blocking / Session / Driven | 🟢 All three | 🟡 Session only | Application execution/reactor |
| Terminal lifecycle | 🟢 Qualified | 🟢 Qualified | Resource choice and call ordering |
All input, candidates, diagnostics, hints and documents are bounded. Rich results
bind to DraftRevision; successful text or cursor changes invalidate earlier
analysis automatically.
Good fits: deterministic CLIs, database and admin consoles, debugger frontends, model clients, network clients with an existing reactor, and C/C++ command consoles.
Outside its job: full-screen dashboards, parsing, shell semantics, durable history storage and application scheduling. Sensitive input and bounded producer arbitration are planned for the first public release but are not present today; current output calls still pass through one serialized owner.
The application keeps its parser, state, execution and scheduler. REPLAI's public blocking, session, driven and C ABI surfaces converge on one interaction engine, renderer and terminal contract, realized natively on Linux and macOS.
The input pipeline and analysis pipeline are independent ownership paths:
input bytes → decoder → normalized action → editor/interaction → layout/damage → effects
draft N → immutable snapshot → HOST ANALYSIS → result @ N → current?
├─ no → Stale
└─ yes → present/apply
A stale result cannot mutate the draft or emit presentation. Resize and serialized host output do not change the draft revision, so current presentation can be laid out and restored without asking the host to parse again.
Editorowns the bounded UTF-8 draft, grapheme/word edits, delta undo/redo, kill/yank, history mechanics andDraftRevisionwithout requiring a terminal.- Analysis contracts own immutable snapshots, stale checks and bounded completion, validation and presentation structures.
Interactiongives blocking, session and driven hosts one lifecycle and one serialized mutation boundary.- Presentation turns safe prompts, completion, diagnostics, hints and documents into shared layout and render damage.
- The terminal contract owns admission, decoding, readiness, geometry and restoration; Linux and macOS provide the native resource realization.
- C ABI 1 adapts the same engine through opaque handles at its documented, deliberately smaller surface.
Editor is terminal-independent. Frames, decoder state and terminal mutations
remain private. The architecture contract maps these
responsibilities to source owners; cargo doc --no-deps renders method-level API
documentation.
Until crates.io publication, pin the qualified runtime implementation checkpoint:
[dependencies]
replai = { git = "https://github.com/mothx9/replai", rev = "81306658151fb8a0fff9b10bfda698e79fb54e15" }This immutable checkpoint carries the qualified configurable-keymap, completion-helper and autosuggestion implementation. Package and external-consumer evidence is recorded in the packaging dossier and the current boundary dossier. Exact Git pins keep pre-release consumption deliberate; no crates.io package has been published yet.
A current stable Rust toolchain is used today. The unpublished 0.1.0 candidate
declares Rust 1.98.1 as its MSRV. Runtime dependencies
are unicode-segmentation, unicode-width, rustix on Linux/macOS and nix for
macOS waiting. There is no daemon, background process or required async runtime.
The smallest real host remains small:
use replai::{Editor, Interaction, Prompt, ReadOutcome};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut input = Interaction::new(Editor::new(65_536, 100));
loop {
match input.read_line(Prompt::new("demo")?)? {
ReadOutcome::Submitted(text) => println!("received: {text}"),
ReadOutcome::Interrupted => {},
ReadOutcome::EndOfInput => break,
}
input.editor_mut()?.clear();
}
Ok(())
}The terminal is restored before read_line returns. The host decides what to do
with submission, interrupt and EOF. The complete blocking example
also admits history explicitly.
open → poll → host handles event
↑ │
└─ result / output
submit / interrupt / EOF / close → restored terminal
A session can deliver completion, validation, analysis presentation and
serialized output while the editor stays active. poll(Duration) is a convenience
scheduler with bounded resize observation. The public showcase
is the canonical session example; demo.rs is smaller.
terminal readiness ─┐
network result ─────┤
resize notification ┤
REPLAI deadline ────┘ → host reactor → serialized Interaction calls
Use open_driven or open_with_config, then inspect wait_interest() and
input_source(). Deliver advance(Wake::InputReady), advance(Wake::Resize) or
advance(Wake::Deadline(token)), refreshing interest after each operation.
The driven example owns the wait. With no readiness or
deadline, REPLAI requires no periodic wake. No Tokio or signal handler is required.
One AnalysisSnapshot contains coherent text, cursor and revision. It can leave
the interaction while the host parses once and derives completion, validation
and presentation independently. REPLAI owns provenance and safe application;
the host owns meaning, context, cadence and cancellation.
A session receives Event::CompletionRequested; the host returns ordered
candidates whose display label, annotation and insertion text may differ:
use replai::{AnalysisOutcome, CompletionCandidate, CompletionError, CompletionSet, Interaction};
fn offer_build(input: &mut Interaction) -> Result<AnalysisOutcome, CompletionError> {
let snapshot = input.analysis_snapshot();
let candidate = CompletionCandidate::new(0..snapshot.text().len(), "build ", "build")?
.with_annotation("Build the project")?;
input.present_completions(CompletionSet::new(snapshot.revision(), vec![candidate])?)
}Tab/arrow navigation does not change DraftRevision; Enter accepts the candidate
before a later Enter can submit. Delayed stale sets produce no menu, terminal
bytes or draft mutation. Runnable completion ·
contract.
With SubmissionPolicy::Validated, Enter creates a revision-bound request:
SubmissionRequested(snapshot) → HOST
Complete → submit the exact validated revision
Incomplete → insert newline and continue
Invalid → retain draft and show safe diagnostics
The delivery path stays small:
use replai::{AnalysisSnapshot, Interaction, ValidationDisposition, ValidationError,
ValidationOutcome, ValidationResult};
fn return_decision(input: &mut Interaction, request: AnalysisSnapshot,
decision: ValidationDisposition) -> Result<ValidationOutcome, ValidationError> {
input.apply_validation(ValidationResult::new(request.revision(), decision)?)
}A stale decision cannot submit, insert a newline or display a diagnostic. REPLAI owns continuation layout, multiline vertical navigation and Tab indentation in continuation whitespace; the host owns grammar. Runnable validator · contract.
AnalysisPresentation carries ordered, non-overlapping AnalysisSpan ranges and
an optional Hint at one revision. The host classifies text into generic roles;
REPLAI never recognizes a keyword, command or path.
A hint is visible as [~…] but is never editor text, history or submitted input.
It is suppressed while completion is open and returns after dismissal if still
current. Insertion continues through completion or revision-bound replacement.
Plain mode drops color-only spans while retaining explicit non-canonical hint
markers. Runnable analysis ·
contract.
Interactive presentation covers prompts, continuations, completion, diagnostics and hints. Structured documents cover headings, facts, lists, responsive tables, status and literal blocks. The host supplies safe structure rather than ANSI or manually padded columns:
use replai::{Block, Document, Severity, Text, Theme};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let document = Document::new(vec![
Block::Heading { level: 1, text: Text::new("Workspace")? },
Block::KeyValue(vec![(Text::new("Mode")?, Text::new("local")?)]),
Block::Status { severity: Severity::Success, text: Text::new("Ready")? },
])?;
print!("{}", document.render(60, Theme::new(false, false, None))?);
Ok(())
}# Workspace
Mode local
[ok] Ready
Interaction::output_document uses the same model while editing, then restores
the exact current interactive surface. Narrow tables become stacked records;
NO_COLOR retains structural labels. Structured example ·
report · contract.
C ABI 1 exposes opaque handles, explicit events and caller-owned UTF-8 copy buffers. It uses the same engine. A polling excerpt:
#include "replai.h"
replai_status next_event(replai_handle *input, replai_event *event) {
replai_status status;
do {
*event = (replai_event){.struct_size = sizeof *event,
.abi_version = REPLAI_C_ABI_VERSION};
status = replai_poll(input, 100, event);
} while (status == REPLAI_OK && event->kind == REPLAI_EVENT_NONE);
return status;
}Build staged static/shared artifacts and the complete C host:
cargo build --locked --release -p replai-c
python3 tools/stage_c.py --prefix /tmp/replai-install
export PKG_CONFIG_PATH=/tmp/replai-install/lib/pkgconfig
cc examples/c/demo.c $(pkg-config --cflags --libs replai) \
-Wl,-rpath,/tmp/replai-install/lib -o /tmp/replai-demo
/tmp/replai-demoUse an absent or empty staging directory. Installed consumers need a C/C++ toolchain and staged artifacts, not Rust or a checkout. ABI 1 provides session polling, synchronous replacement, direct submission, prompts and plain coordinated output. Rich candidates, revisioned analysis, validation, documents and driven embedding remain Rust-native. C installation and ABI contract.
This is the currently qualified platform surface, not a published release claim.
| Target | Rust terminal | C ABI 1 | Qualification status |
|---|---|---|---|
| Linux GNU x86_64 | Blocking / Session / Driven | Static + shared | 🟢 Qualified release target; real PTY + Valgrind |
| Linux GNU ARM64 | Blocking / Session / Driven | Static + shared | 🟢 Qualified release target; native real PTY + Valgrind |
| macOS ARM64 | Blocking / Session / Driven | Static + dylib | 🟢 Qualified release target; native real PTY + leaks |
| Windows x86_64 | Portable models only | No terminal adapter | ⚪ Portable only; no terminal backend |
| macOS Intel | Source may compile | Unqualified | 🟡 Not release-qualified |
| Linux musl / other targets | Source portability only | Unqualified | 🟡 Not release-qualified |
Interactive admission requires matching TTYs, restorable modes, usable dimensions
and required cursor/erase mechanics. Conservative entry points refuse absent or
TERM=dumb evidence. NO_COLOR is presentation policy. Without admitted
bracketed paste, multiline bytes are ordinary edits and lose paste atomicity.
The expanded v0.1 plan requires a native Windows x86_64 Rust terminal runtime
before candidate freeze; the table records what exists now.
- Stale host results cannot mutate a newer draft or emit presentation.
- Invalid host ranges and payloads are rejected before editor mutation; safe host text rejects terminal controls.
- Capability mismatches are refused before raw mode where required.
- Serialized external output restores the current draft, cursor and valid presentation.
- Drafts, history, candidates, diagnostics, hints and documents have explicit bounds.
- One host owns and serializes
Interaction; close attempts restoration and reports cleanup failure through the explicit boundary.
The implementation crate forbids unsafe Rust. FFI unsafety is confined to the adapter and its documented pointer preconditions. This is a memory-safety posture in addition to the logical contracts above; it is not a security certification.
Lifecycle misuse, unsupported capabilities, I/O failure, malformed host data,
stale analysis and capacity exhaustion remain distinct. REPLAI rejects before
mutation when possible, retains the draft after recoverable semantic rejection,
and returns typed Stale outcomes for results that are valid but obsolete.
Terminal failures trigger cleanup; explicit close reports restoration failure
where the OS still makes observation possible.
Arbitrary allocator abort, process-wide OOM and SIGKILL recovery are outside the contract. Exact error taxonomy and recovery rules live in the interaction contract.
Caller descriptors remain caller-owned. REPLAI duplicates terminal resources for
an open interaction, restores/releases those duplicates on close and retains the
editor/history after close. Drop attempts cleanup without panicking; explicit
close is the reporting boundary. Driven hosts own waiting and resize delivery.
Interaction has single-owner serialized mutation semantics. Immutable snapshots
may be analyzed elsewhere while the host continues editing; returned results are
serialized back through revision checks. REPLAI does not promise shared mutable
access or independent stdout/stderr writers.
Representative results from the frozen Q2 registration:
| Recorded workload | Median | p95 | Allocations | Encoded bytes |
|---|---|---|---|---|
| Warmed append, 1 KiB draft | 32 ns | 48 ns | 0 | 0 |
| 1,000-byte edit + submission | 44.7 µs | 45.3 µs | 1,118 | 1,042 |
| Completion menu show | 24.8 µs | 25.2 µs | 161 | 1,312 |
| Validation result | 23.9 µs | 24.3 µs | 123 | 1,235 |
| Analysis presentation, 64 KiB | 1.32 ms | 1.33 ms | 159 | 37 |
| Analysis presentation, 1 MiB | 21.15 ms | 21.18 ms | 159 | 37 |
Source 6975c0979a1fd13f619f2d079b7494945ca18c5e, runtime tree
12b9cd0e58ef8d2dfe6c1b91185fd21b05a7aa9e; Spark ARM64, Linux
6.17.0-1021-nvidia, Rust 1.98.1/LLVM 22.1.8. Five control batches and 31
measured repetitions per batch; allocations use a separate build.
All 32 workloads, thresholds and methodology.
These measurements characterize recorded workloads. They are not a universal ranking of terminal libraries. Deep-cursor multiline layout still traverses the prefix; Unicode costs depend on content; serialized host output is synchronous. Those measured limits remain visible rather than being converted into an SLA.
REPLAI is an unpublished 0.1.0 candidate. The Rust API is not frozen, C ABI 1 is
qualified at its current bounded scope, and crates.io publication has not
occurred. Consume Rust through the exact Git pin above; the declared and
qualified candidate MSRV is Rust 1.98.1. Today Linux GNU x86_64/ARM64 and macOS
ARM64 have native runtime evidence, while Windows has portable-core coverage
only. Daily-driver word editing, bounded undo/redo, kill/yank and provider-backed
literal history search, configurable mappings, completion helpers, paged large
sets and autosuggestion are now present. The expanded first-release plan still requires long-lived output,
sensitive input, native Windows Rust runtime, complete UX/DX and agentic integration
before final hardening and freeze. Planned work is not current API.
Release scope · Roadmap.
CI on master checks the current source. Exact campaign identities live in engineering dossiers.
| Evidence class | Current coverage |
|---|---|
| Native interaction | Real Linux x86_64/ARM64 and macOS ARM64 PTYs, lifecycle/resource stress, restoration and failure paths |
| Adversarial models | Five fuzz targets, 100,000 generated semantic sequences and retained corpus replay |
| Memory and FFI | Linux Valgrind, macOS leaks, ABI layout/symbol checks, static/shared C11 and C++17 consumers |
| Portable core | Windows editor, engine and analysis models; no terminal-runtime inference |
| Public surface | Compiled README snippets, runnable examples, deterministic real-PTY PNG/GIF and Q2 regression checks |
See the release-hardening dossier for campaign identities, budgets and findings, and the development guide for exact local, native and asset-check commands.
REPLAI is a line-oriented interaction library. It is not a shell, parser, command language, full-screen TUI framework, async runtime, application scheduler, history database, agent runtime or plugin framework. Current source has no sensitive-input mode, sustained-output service, producer arbitration or Windows terminal backend; those are explicit pre-release gaps rather than permanent ownership exclusions.
- Start: examples and use cases.
- Integrate: Rust interaction/embedding, C installation and ABI.
- Present: documents, prompts, themes and width.
- Understand: architecture, documentation owners.
- Verify: development, release hardening.
- Track: roadmap, release scope, changelog.
Optional producer metadata records cross-repository contract changes. It is not required to build or run REPLAI.
Useful issues include OS, terminal, a minimal reproduction and expected versus observed behavior. Changes should name the affected boundary and supply evidence when behavior changes. See CONTRIBUTING.md or open an issue.
MIT.



