Releases: DrOlu/RTerm
Release list
RTerm v3.9.2
RTerm v3.9.2 — AI-Native Terminal App by Hyperspace Technologies
v3.9.2 (2026-09-24)
Fix: the bundled neuralOS engine shipped without its exec bit — every
neuralos_ask/neuralos_graph call in the desktop app died with
engine exited EACCES: (empty stderr).
Root cause chain: curl -o in the release workflow writes files with mode
0644 and the workflow never chmod'd them; electron-builder's extraResources
preserves that mode into the packaged app; and resolveEngine checked only
existence (F_OK), so the un-runnable bundled engine permanently shadowed
perfectly good alternatives (the shared cache, <instancesDir>/engine/needle).
Fixes, layered so this class of bug cannot recur:
resolveEnginenow checks executability (X_OK), not existence. A
present-but-unexecutable candidate is skipped (never a hard stop), so a
broken bundle falls through to the next runnable engine.- One-shot chmod recovery: a 0644 engine we own is fixed in place
(chmod 0755 + re-probe) instead of skipped — covers curl -o, zip/tar
extraction, and copy flows that drop the exec bit. - EACCES at spawn time is named, with the fix in the message
(engine not executable (path) — restore the exec bit (chmod +x) or set neuralos.engineBin/engineWeights) instead of the cryptic
engine exited EACCES:with a trailing colon and no stderr. - Exhausted-path errors now explain every failure: when no candidate is
usable, the error lists the found-but-not-executable paths alongside the
auto-download failure, so operators see why every route was exhausted. - Release workflow chmods the downloaded engines on all 4 platforms and
the verify steps now asserttest -x(mac + Linux) so an un-runnable
engine can never ship again.
Also fixed in the same review (all error-as-data, no thrown exceptions):
defaultExecpreserved a realEACCEScode but reported timeout kills
(SIGTERM from our own timeout) as a genericexit 1— now reported as
killed (SIGTERM)so timeouts are distinguishable from crashes.truncate(undefined)crashed (JSON.stringify(undefined)is
undefined, not a string) — now renders'null'honestly.graphProbethrew on a corrupt/non-arrayneedle_menu.jsoninstead of
answering with an error — every other read path in the plugin already
reports errors as data; this one now does too.
Spec: 9 new tests (section 12) — 0644-bundle skip, chmod recovery, EACCES
naming, non-EACCES crash shape, real-EACCES code preservation, timeout-kill
honesty, truncate(undefined), corrupt menu, non-array menu. 51 total.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.9.2-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.9.2-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.9.2-x64.exe |
| Linux x64 (AppImage) | RTerm-3.9.2-x64.AppImage |
| Linux x64 (deb) | RTerm-3.9.2-x64.deb |
| Linux x64 (pacman) | RTerm-3.9.2-x64.pacman |
| Linux x64 (rpm) | RTerm-3.9.2-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.9.2-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.9.2-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.9.2-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.9.1
RTerm v3.9.1 — AI-Native Terminal App by Hyperspace Technologies
v3.9.1 (2026-09-24)
neuralOS is now visible in Settings → Plugins. The plugins tab renders a
fixed set of per-plugin settings panels, and neuralOS had none — the plugin
loaded (its four tools appear under Plugin tools) but had no settings form.
New panel: instances root, python interpreter, engine binary/weights overrides,
auto-provisioning toggle, cache dir, timeout, plus an Enabled switch the
plugin now honors (neuralos.enabled=false registers zero tools). Blank
fields fall back to the bundled engine → shared cache → <instancesDir>/engine.
Also: settings-block enable gate in the neuralos plugin (spec 42 tests).
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.9.1-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.9.1-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.9.1-x64.exe |
| Linux x64 (AppImage) | RTerm-3.9.1-x64.AppImage |
| Linux x64 (deb) | RTerm-3.9.1-x64.deb |
| Linux x64 (pacman) | RTerm-3.9.1-x64.pacman |
| Linux x64 (rpm) | RTerm-3.9.1-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.9.1-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.9.1-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.9.1-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.9.0
RTerm v3.9.0 — AI-Native Terminal App by Hyperspace Technologies
v3.9.0 (2026-09-24)
neuralOS native — on-device data agents as first-class RTerm tools, bundled.
A new official plugin, neuralos, wires the neuralOS instances
(~/neuralos-instances — verified probe menus over real data sources) into
the agent as four tools: neuralos_list_instances, neuralos_ask
(plain-English question -> the 121M on-device engine selects the probe, the
instance bridge executes it, a verified digest comes back), neuralos_graph
(relationship maps, executed directly by probe name), and neuralos_admin
(write probes behind a confirm="yes" interlock). Settings block neuralos
(instancesDir, pythonBin, engineBin/engineWeights, autoDownload); config also
via NEURALOS_* env.
True install-and-nothing-else, on every channel:
- Desktop: the engine binary + 35 MB
needle3.cactweights are
downloaded at build time and shipped inside every installer (macOS ARM64,
Windows x64, Linux x64 + ARM64) at<resources>/neuralos/— a build-time
verify gate fails the release if the bundle is missing. - npm (
rterm-backend+neuralos, the same package under both names):
the plugin auto-provisions~/.cache/neuraloson first use — one ~36 MB
fetch from the public Cactus-Compute/needle3 release, then offline
forever. Publishing is now a first-class release-workflow job (was manual).
Also new: the npm publish pipeline (scripts/publish-npm.mjs +
scripts/npm-package.template.json) assembles the standalone backend into
the published layout (bin/gybackend.cjs + plugins/ + README) and publishes
both names at the repo version, driven by the NPM_TOKEN secret.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.9.0-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.9.0-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.9.0-x64.exe |
| Linux x64 (AppImage) | RTerm-3.9.0-x64.AppImage |
| Linux x64 (deb) | RTerm-3.9.0-x64.deb |
| Linux x64 (pacman) | RTerm-3.9.0-x64.pacman |
| Linux x64 (rpm) | RTerm-3.9.0-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.9.0-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.9.0-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.9.0-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.9
RTerm v3.8.9 — AI-Native Terminal App by Hyperspace Technologies
v3.8.9 (2026-09-18)
Four fixes for the extended-chat freeze family and session durability — all
found by reading the actual code paths, three of them live-observed.
The MemorySaver checkpoint leak — the real extended-chat freeze root cause
LangGraph's MemorySaver keeps every checkpoint of every graph step,
forever: storage[threadId][ns][checkpoint.id] holds a serialized copy of
the full conversation state per step. A 100-step multi-tool run retains
~100 copies in RAM — unbounded growth, GC thrash, and the "app freezes in
extended chats until force-quit" behavior. The earlier pruning work (v3.8.3)
shrank each blob but never evicted old blobs; the count kept climbing.
SafeMemorySaver now evicts: after each put it keeps only the newest
8 checkpoints per (thread, ns), enforced on all three put paths (normal,
OOM-retry, skip-persist). Insertion order is tracked per (thread, ns) since
MemorySaver exposes no timestamps; untracked ids (from before this process)
are kept rather than risk dropping the resume point. Safe because LangGraph
resumes from the latest checkpoint and parent-chain walking touches only
recent entries.
Interruption marker — force-quit recovery for chat sessions
A force quit mid-run leaves the session's last AI message partial, but
stored looking exactly like a completed turn. After restart the model reads
it as complete and treats the next message as a fresh topic — the
interrupted task is silently abandoned.
Now a run marker (in the history_meta table, survives restart) is set
just before graph.invoke and cleared in the run's finally block. Only a
hard kill skips finally, so a leftover marker means the run was
interrupted; the next run detects it, injects a system notice telling the
model the prior response may be partial (with the interrupted task's input
preview), and offers to continue rather than start from scratch.
Ordering bug caught in review before release: the marker was initially
set before the detection block — every run found its own marker, injected
a false notice, and consumed the real one, so a genuine force-quit left
nothing behind. The feature was inverted. The set now happens after the
restore path has consumed any leftover marker.
Rename race — renames reverted by the run-end save
Renaming a chat session during a running agent task silently reverted when
the task finished: the agent's in-memory session object carried the old
title from run start, and the store's upsert (title = excluded.title)
wrote it back over the rename at run end. ChatHistoryService.saveSession
now treats the stored title as authoritative for an existing session —
the in-memory title only names a brand-new session. Same discipline the
store already applied to created_at, which is why creation dates never
had this bug.
Also
- Dead code documented:
lastCheckpointOffsetis written on every run but
has no reader — the v3.2.5 "recovery can resume from this offset"
promise was never built. Left in place (harmless) pending a real consumer. GatewayService.resumeTaskremains an empty stub.
Tests
safeMemorySaverEviction.extreme.spec.ts(6) — retention window, per-thread
isolation, getTuple resolves newest after eviction, deleteThread, and the
control: vanilla MemorySaver retains all 50 (the leak), SafeMemorySaver caps.runMarker.extreme.spec.ts(7) — marker survives store close+reopen (the
force-quit case), per-session isolation, corrupt marker reads as absent,
consume-once semantics.renameRace.extreme.spec.ts(4) — the exact live race: load → rename
mid-run → save the stale object → the rename survives.- All wired into
test:backend-unit-extreme.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.9-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.9-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.9-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.9-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.9-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.9-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.9-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.9-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.9-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.9-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.8
RTerm v3.8.8 — AI-Native Terminal App by Hyperspace Technologies
v3.8.8 (2026-09-18)
New: inbound invoke — mesh peers can now drive RTerm's agent
Found live: the ReactorPro manifest advertised an invoke skill, but
defaultServeSkills had no handler for it — a peer dispatching invoke got
SKILL_NOT_FOUND while the manifest promised "invoke routes a prompt into a
real RTerm agent turn". RTerm could call other agents but couldn't be
usefully called by them.
invoke is now real. A mesh peer sends a prompt; RTerm runs it as a
genuine agent turn — tools, command policy, and the audit ledger all
apply — and the final assistant text goes back over the mesh.
- New
runAgentTaskPluginContext hook — one real agent turn, resolve
with the final answer. Wired on the daemon and desktop; absent in bare
test harnesses, whereinvokereturns a clearINVOKE_UNAVAILABLEerror
instead of pretending. - Prompt extraction accepts
arguments.prompt(the gateway's shape),
prompt,text,message, or a bare string. conversation_idround-trips — a peer that passes the previous
reply'sconversation_idcontinues the same agent session.- Budget-aware — the agent turn is capped at
dispatchTimeout − 10s
(default 170 s) so the reply reaches the caller before its own mesh
dispatch timeout fires.
Two live-found details worth recording:
sayevents are deltas, not full text. The first implementation
captured only the lastsayevent and "PONG" came back as "ONG" — the
final streamed fragment. The publisher-chaining hook now accumulates
saydeltas in order; the concatenation is the answer.- The event publisher is chained, not replaced —
sayevents for the
mesh-invoke session are captured while everything still passes through to
the gateway's broadcast unchanged, and the original publisher is restored
infinally.
Live-verified end to end: a Synapse-convention dispatch of invoke to
RTerm's inbox now returns a real agent answer (previously SKILL_NOT_FOUND),
and RTerm → grip-cli-001 invoke returns a real LLM reply (previously
verified; unchanged).
Spec: 10 new inbound-invoke cases (prompt extraction, conversation
persistence, budget clamping, unavailable-runtime degradation).
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.8-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.8-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.8-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.8-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.8-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.8-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.8-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.8-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.8-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.8-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.7
RTerm v3.8.7 — AI-Native Terminal App by Hyperspace Technologies
v3.8.7 (2026-09-18)
Fixed: ReactorPro gateway dropped RTerm from mesh discovery
Three wire-shape bugs in the reactorpro-bridge plugin made RTerm
invisible to ReactorPro gateway discovery — even though every envelope
signature verified correctly.
identityvsid— the manifest advertisedidentity:where the
gateway'sManifeststruct unmarshalsjson:"id". The gateway's
manifestMatchesdrops a manifest whose ID is empty, so every manifest
RTerm published was discarded at the filter: signed correctly, silently
dropped.- Skills as bare strings — the gateway's
Skillstruct unmarshals
[]{id,name,description}objects; bare strings became empty entries,
breakingskill_iddiscovery filters. - Payload nesting — register/discover payloads were wrapped under
{manifest: {...}}, but the gateway attaches the bare manifest. The
plugin's reply parser now accepts all three shapes the wire actually
carries: bare manifest,{agents:[...]}, and the legacy nested form.
Live-verified both directions against the real gateway:
- RTerm
discoverPeers→ the gateway answers (reactorpro/bionic-01) - The gateway's own Go discovery (
TestRtermBridgeReverseDiscover,
RTERM_BRIDGE_LIVE=1) → listsreactorpro/rterm-01alongside
grip-001, agentspan-001, grip-cli-001, omp-cli-001
Spec: 39/39 — 11 new manifest-shape cases pin the gateway's struct
contract (id key, skills as objects, bare-manifest payloads) so this
class of bug is loud instead of silent.
The lesson: a signature verifies bytes, not semantics. The signing
cross-verify passed while discovery was broken — interop contracts need a
test per direction per semantic layer.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.7-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.7-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.7-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.7-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.7-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.7-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.7-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.7-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.7-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.7-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.6
RTerm v3.8.6 — AI-Native Terminal App by Hyperspace Technologies
v3.8.6 (2026-09-18)
ReactorPro Mesh Bridge settings panel (desktop Settings UI)
The reactorpro plugin shipped in 3.8.5 with its backend settings wiring
complete but no Settings panel — configuration was only reachable via
settings:set or by asking the agent. This closes that gap: the desktop
Settings view now shows a ReactorPro Mesh Bridge panel (enabled, NATS
URL, mesh prefix, agent id, display name, identity file, auto-serve),
following the same generic plugin-panel pattern as webIntel / nats /
synapse / numbat / monid. Blank fields are omitted on save so server
defaults apply.
The two fields that deserve warnings carry them in the UI:
- agent id — PERMANENT once an identity exists. It is hashed into the
fingerprint; changing it means a new identity peers must re-pin. - identity file — minted on first use (0600). Back it up: losing it means
peers that pinned the old fingerprint will refuse this instance.
Settings round-trip guard
New test pins the v3.1.3 lesson for this block: the reactorpro settings
block must survive save+reload. It shipped with the pickBackendSnapshot
whitelist key, but a future refactor of that list would have silently wiped
it — now that regression is loud instead of silent. Settings migrations
spec: 23/23.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.6-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.6-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.6-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.6-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.6-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.6-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.6-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.6-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.6-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.6-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.5
RTerm v3.8.5 — AI-Native Terminal App by Hyperspace Technologies
v3.8.5 (2026-09-17)
New plugin: reactorpro-bridge — full-duplex ReactorPro mesh citizen
Makes RTerm a first-class verified peer on a ReactorPro mesh. ReactorPro
desktops and edges see RTerm like one of their own — signatures check, the
fingerprint binds, gated invoke included.
- Discover live mesh peers and their manifests; dispatch signed tasks;
register with the mesh registry; and — the half that matters — serve
inbound requests onmesh.agent.{id}.inbox(auto-started), so other agents
can call RTerm, not just be called by it. Signed heartbeats keep the peer
alive in the directory. - Speaks the ReactorPro wire convention (sig/pub/fp Ed25519, v0.3.0 envelopes)
over a shared NATS server — the same convention the ReactorPro gateway
enforces. The signing layer mirrors the gateway'sidentity.go
byte-for-byte: length-prefixed field digest over
v,id,type,ts,from,to,task_id,in_reply_to,fp,[trace],[error]+sha256(payload);
fingerprint =sha256(agentID + "\n" + raw_pubkey)[:16]. - 9 tools (
reactorpro_health/discover/dispatch/invoke_edge/register/ agents_summary/serve/serve_status/identity), thereactorpro_mesh_event
trigger, and areactorpro-mesh-peerspanel. - Identity is minted once and persisted (0600). The agent id is permanent —
it is hashed into the fingerprint, so changing it means a new identity peers
must re-pin. A tampered identity file is rejected on load. - Settings: new
reactorproblock (url/servers/prefix/agentId/name/
identityPath/capabilities/auth incl. secretRefs/autoServe/dispatchTimeout),
withReactorProSettings+normalizeReactorProSettings+ the snapshot
whitelist key — a settings block missing from that whitelist is silently
wiped on save (the v3.1.3 lesson, applied up front this time).
Cross-verified against the real Go gateway (rterm_crossverify_test.go):
the plugin's signed envelope passes the gateway's VerifyEnvelope, the
fingerprint binds to the claimed sender, SigningPayload matches
byte-for-byte, and the gateway's own signed envelope verifies under the
plugin's rules. 28/28 spec cases.
Fixture-fidelity fix (found live during that cross-verify)
The cross-verify fixture is now written compact. The gateway's
Envelope.Payload is a json.RawMessage, which captures payload bytes
verbatim from the file — a pretty-printed fixture made the gateway re-hash
different bytes than were signed (whitespace changed the digest) and fail,
even though the real wire exchange was correct all along. The fixture is now
byte-faithful to the wire, with a comment explaining why.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.5-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.5-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.5-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.5-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.5-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.5-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.5-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.5-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.5-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.5-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.4
RTerm v3.8.4 — AI-Native Terminal App by Hyperspace Technologies
v3.8.4 (2026-09-12)
history:search no longer freezes the app
The gateway's history:search called getAllSessions(), which JSON.parses
every message of every session in one synchronous burst before comparing a
single character. On a 1.6 GB multi-session store that is seconds of blocked
event loop — and because better-sqlite3 is synchronous and runs on the same
thread, the whole UI froze while searching.
Searching is now bounded: searchChatHistoryBounded() reads one session,
searches it, releases it, then yields to the event loop before the next.
Peak memory becomes one session instead of the whole store, and the loop is
blocked for one session at a time instead of all of them.
- New
searchBounded()on the gateway's history bridge; thehistory:search
handler prefers it and falls back togetAllSessions()when absent (e.g. the
desktop app's in-memory bridge), so behaviour stays correct either way. listChatSessions()is now documented as a freeze hazard: it parses every
message of every session and is only for genuinely whole-store work. Callers
that need a session list uselistChatSessionSummaries()(COUNT only).
Deterministic model errors fail fast (retries were pure latency)
invokeWithRetry retried every non-abort error, so a truncated response or
a code bug burned 4 attempts plus ~13 s of backoff and then failed anyway, with
"Retrying (3/4)…" shown in the UI the whole time.
Only genuinely transient failures retry now: network/socket errors, timeouts,
429, and 5xx. Deterministic errors (4xx, truncation, malformed payloads) fail
fast with the real reason.
The subtle part is that an empty response has two very different causes that
arrive as the same thrown message:
Model stream ended with an empty unusable response (finish_reason=X).
finish_reason |
Cause | Behaviour |
|---|---|---|
error |
provider-side, often transient | retry |
length |
truncated answer, repeats | fail fast |
content_filter |
policy block, repeats | fail fast |
The classifier splits on the finish reason rather than the wording. (An earlier
revision matched the blanket substring "finish_reason=" and killed the
provider-error retry, which a behavioural spec asserts must happen.)
Fixed: "lengthlength" finish reason garble
getRawFinishReason read choice.finish_reason from langchain chunks, whose
streamed value can be a concatenation of every chunk's reason — a streamed
response ending with finish_reason: "length" produced "lengthlength", which
rendered into errors, logs and the UI as "lengthlength, length".
normalizeFinishReason() collapses a value that is exactly a known reason
repeated 2–5 times back to the canonical token. Detection is deliberately
conservative: an unrecognised provider string is returned untouched, so no
canonical value is invented.
Tests
historySearchBounded.extreme.spec.ts(7 cases) — loads one session at a
time, yields to the event loop, preserves ranking/limit/truncated semantics,
skips a session deleted between summary and load.runtimeRetry.extreme.spec.ts(9 cases) — pins the finish-reason split,
abort behaviour, transient retries, and deterministic fail-fast.- Both wired into
test:backend-unit-extreme.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.4-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.4-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.4-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.4-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.4-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.4-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.4-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.4-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.4-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.4-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng
RTerm v3.8.3
RTerm v3.8.3 — AI-Native Terminal App by Hyperspace Technologies
v3.8.3 (2026-09-11)
Incremental history save — the real freeze fix
saveChatSession ran DELETE ALL + INSERT ALL on every save, rewriting
the whole session payload. Measured on a 6,102-message / 116.9 MB session, the
old block cost 2.59 s per save, of which 1.50 s was JSON.parse alone
(SQLite I/O was only 0.07 s delete + 0.37 s insert + 0.65 s flush).
Saving is now incremental — only rows that actually moved are written:
- New
loadSessionMessageState()reads rawmessage_data_jsonwithout
parsing (the parse was the expensive half and is unnecessary for an
equality test). applyChatSessionDelta()upserts only changed rows and deletes only absent
ones (compaction / rollback), inside one transaction.replaceAllMessages()handles the rare reorder case.
Two silent-staleness bugs fixed on the way in:
digestForwas a 200-char prefix fingerprint. A message whose body grows
past character 200 — exactly what streaming does to the last AI message —
kept an identical prefix, so the row was skipped and the persisted history
silently stayed stale. It now fingerprints the full serialized body.replaceAllMessagesupserted in place, which collides on the
(session_id, position)PRIMARY KEY during a reorder (UNIQUE constraint failed). Any chat reorder/branch would have crashed the save. It now clears
the session's rows and re-inserts inside one transaction.
Two full-session reads removed from hot paths
ChatHistoryService.saveSession called loadChatSession() purely to learn
createdAt, and AgentService_v2.trySaveSessionFromCheckpoint called
loadSession() for a default it never used — each parse discarded immediately.
Both now read a single indexed row via the new getChatSessionMeta() /
getChatSessionCreatedAt(). The checkpoint path still preserves the session
title (a blank default would have renamed sessions to "New Session").
Tests
- New
HistorySqliteStore.delta.extreme.spec.ts(7 cases, wired into
test:backend-unit-extreme): growth past char 200 reaches disk, no-op saves
don't duplicate rows, append / remove / reorder / createdAt preservation,
and emptying a session. AgentSettingProfileService.extreme.spec.tsasserted the literal
'standard'where the contract is "apply restores the saved value". The
v3.8.2 default change (standard → smart) broke it; it now captures the saved
value so it cannot rot again. v3.8.2 shipped with this spec failing.
Downloads
| Platform | File |
|---|---|
| macOS ARM64 | RTerm-3.8.3-arm64.dmg |
| Windows x64 (Portable) | RTerm.Portable.3.8.3-x64.exe |
| Windows x64 (Setup) | RTerm.Setup.3.8.3-x64.exe |
| Linux x64 (AppImage) | RTerm-3.8.3-x64.AppImage |
| Linux x64 (deb) | RTerm-3.8.3-x64.deb |
| Linux x64 (pacman) | RTerm-3.8.3-x64.pacman |
| Linux x64 (rpm) | RTerm-3.8.3-x64.rpm |
| Linux ARM64 (AppImage) | RTerm-3.8.3-arm64.AppImage |
| Linux ARM64 (deb) | RTerm-3.8.3-arm64.deb |
| Linux ARM64 (rpm) | RTerm-3.8.3-arm64.rpm |
Install
macOS: After installing, run xattr -cr /Applications/RTerm.app to remove quarantine.
Linux AppImage: chmod +x RTerm-*.AppImage && ./RTerm-*.AppImage
Linux deb: sudo dpkg -i RTerm-*.deb
Linux rpm: sudo rpm -i RTerm-*.rpm
Contact: rterm@hyperspace.ng