Releases: MrCipherSmith/keryx
Release list
v0.2.67
[0.2.67] — 2026-08-24
Added
-
A suggested next step after every settled turn (Claude-style): when the
main agent finishes and the queue is empty, a short model-generated follow-up
appears in the composer placeholder. Tab / Right-arrow inserts it without
submitting; Enter on the empty composer submits it directly; typing dismisses
it. Fail-closed: no credential, a timeout, or a.reply shows nothing and
never blocks the shell. -
keryx workspace dismiss-candidate <evidence-path|session-id>— UNBOUND
candidates (wrap-up ran with no workspace bound) can now be dismissed instead
of lingering incatch-up//reviewforever: the artifact is removed and a
*-unbound-dismissed.jsonreceipt is written, after which both the internal
and external-slate readers skip it.
Fixed
/themeswitch did not repaint already-rendered chrome. Only the
chrome's own surfaces were recolored; transcript frames, tone block headers,
dock buttons and sidebar panels kept the old palette's hexes, so dark-to-dark
switches looked like the theme never applied. The tree is now walked with
theme-color remapping (OpenTUI stores colors as RGBA objects).
v0.2.66
[0.2.66] — 2026-08-24
Fixed
-
A typed message in front of a paste vanished from the transcript, leaving
only[pasted N lines]. The composer's submit echo collapsed ANY
multi-line input into that bare placeholder, so typing a question and then
pasting a block after it discarded your own words entirely — the transcript
looked like you'd said nothing. It now keeps your own first line and
summarizes only the rest as a paste count (explain this [+ 12 pasted lines]). The logic was also duplicated between the chat and agent shells;
it is now one shared function. -
Fenced code blocks in a reply had no way to copy them.
y//copyonly
ever reached the block-nav registry (thought/tool/output blocks) — a fence
embedded in the reply text had no registry entry of its own, so there was no
copy path at all. Both now fall back to the most recently rendered code
block when nothing is registered to copy, and the block's header advertises
the shortcut (python · 15 lines · y copy).
Added
- Code blocks get lightweight local syntax highlighting. Comments,
strings, numbers and keywords are colorized via a plain-string tokenizer —
no tree-sitter worker, no network or grammar fetch, so it stays inside flow
109's worker-free, no-egress rendering stance (D-2).
Known gaps
- A paste can occasionally split — part of it lands in the transcript as
a sent message, the rest stays stuck in the input. This traces to an open
upstream bug in@opentui/core'sStdinParser
(anomalyco/opentui#1270,
unterminated bracketed paste), present in both the installed0.4.5and the
latest0.5.7— not fixable from here until it lands upstream.
v0.2.65
[0.2.65] — 2026-08-23
Fixed
-
/game's modal no longer scrolls as a whole and the board is never
clipped. The 0.2.64 prompt card usedflexGrow: 1on a ScrollBox with no
height cap, which made OpenTUI measure the card at the full parent height —
the card ballooned to the whole modal body, pushed the stats/footer out of
view and gave the modal a body-wide scrollbar that also clipped the bottom
of the board. The agent panel now reserves a fixed slice (status + stats
lines), the board is sized from the modal body HEIGHT (cell heights 2..5:
tiny/small/medium/large), and the prompt card is a bounded minmax-style
block (5..14 rows) that scrolls only inside itself. Board + panel now sum
exactly to the body height, so everything is on screen at once on any
terminal of ~30 rows or more. -
The agent panel now shows what the model actually receives and with what
parameters. The prompt card shows the system prompt AND the per-turn user
prompt (the exact board state sent each turn, so you can see how the model
learned your move); the status card shows the provider/model in effect
(auto/autountil the first turn) and the compact last-turn/session stats
(latency, in/out tokens, reasoning/fallback/error flags, fallback/error
counts) on three lines instead of two tall cards. -
Modal tab bodies got a stale 68x13 viewport instead of the real one. At
mount time OpenTUI'swidth/heightgetters still return the last LAYOUT
value (the 72x18 creation-time floor), sorenderTab's context claimed the
panel body was 68x13 even on a normal terminal — the /game board was sized
from that floor. The host now computes the body size deterministically from
the renderer (resolveModalPanelSize), matching the panel's actual resolved
size at open.
v0.2.64
[0.2.64] — 2026-08-23
Fixed
/game's system-prompt card is no longer capped at 6 lines. The agent
panel truncated the prompt the model sees to 6 lines plus "… (N more)" and
left dead space below it. The card now renders the full prompt, flexes to
absorb the leftover body height, and scrolls (wheel, scrollbar, or
j/k/↑/↓ once the scrollbar has focus) when the prompt is taller than the
space the layout leaves it.
v0.2.63
[0.2.63] — 2026-08-23
Changed
/game's agent panel is now real cards with a stats table. The system
prompt, last-turn latency/tokens and session totals were one undifferentiated
dim line; they are now three bordered cards — a status line ("agent is
thinking…" / notice / "waiting for your move"), the system prompt wrapped as
lines (capped at 6 + "… (N more)"), and a side-by-side last-turn/session table
(model, first byte, total, in/out tokens, reasoning/fallback/error flags;
turns, fallbacks, errors, token totals), with long provider/model ids
truncated so a half-width card never clips. Footer hints now say
arrows move/tab games.
Fixed
/game's left/right arrows stopped moving the cursor again. The
multi-tab games-host split (0.2.62) dropped theonArrowKeysclaim the
legacy single-game modal keeps, so the modal host's own tab switch consumed
both arrows andstopPropagation'd them before the game saw them — the
cursor moved up/down but not sideways, and with one game the tab switch was
a silent no-op. The games host now claims both arrows for the active game
through the host'sonArrowKeyshook again (a pure probe; the game's own
keypress handler still applies the move, so each press moves once) and only
falls back to tab switching when the game declines the key.
v0.2.62
[0.2.62] — 2026-08-23
Added
/gameis now a multi-tab games host with an agent-stats panel.
The single tic-tac-toe modal became a component-based games module
(src/tui/games/): oneGameDefinitioncontract (rules, prompts, render,
input) plus a registry, so adding a game is adding one definition — its tab
appears automatically on the shared modal host, with←/→switching
games. Tic-tac-toe itself is split intocore/prompts/layout/render/
input/game. Under the board sits the new agent panel (dim/secondary):
the exact system prompt the model sees each turn, plus per-turn
latency/token stats — provider/model, time-to-first-byte, total time,
input/output tokens, reasoning flag, local-fallback count, errors.runModelTurn
now surfacesusage/latencyMs/reasoningfrom the stream so any caller
can show what an agent turn actually costs./game <seconds>raises the model-turn deadline; the default went from
12s to 60s. Local models are slow, and the stats panel's point is to
observe that latency, not to race it./game 45sets a 45-second deadline
for that modal.
Fixed
- The sidebar now shows provider balance and session usage. A new
Balancerow under Model fetches the ACTIVE provider's balance live
(DeepSeekGET /user/balance, OpenRouterGET /api/v1/credits— the only
registry providers with public balance APIs; the rest render—), on
mount and again on click, honouringKERYX_<NAME>_BASE_URLoverrides. A
newUsagerow shows the cumulative in/out token totals for the session,
fed from the sameio.onUsagestream that drives the header counter.
Both are wired into the agent and chat shells.
v0.2.61
[0.2.61] — 2026-08-23
Fixed
- Web search returned empty results on bun-in-
~/.buninstalls. The
bwrap profile for the sandboxed web worker masked$HOMEentirely
(--tmpfs), hidingprocess.execPathitself when bun lives under home.
The worker could not start and the search bridge silently returned empty
results. The profile now masks only home's secret subdirectories via
defaultReadDenyList, leaving the runtime readable.
v0.2.60
[0.2.60] — 2026-08-23
Fixed
-
/game's cursor would not move left or right.modal-hostclaims both
arrows for its own tab switch and callsstopPropagation(), so the game's
keypress listener only ever saw up/down. The cursor now moves through the
host'sonArrowKeyshook, and left/right are removed from the keypress
handler — that hook returns without stopping propagation, so handling them
in both places would move the cursor two cells per press. -
The board is sized from the modal body width: 9×5 cells where the 33
columns they need fit, the previous 5×3 where they do not. -
A model turn could hang the game indefinitely. There was no deadline on
the provider call, so a stalled request left "agent is thinking…" on screen
withRas the only way out. The turn now has a 12s deadline; on timeout —
or on a reply that names no free cell — the game plays a local move (win,
block, centre, corner) and says so, instead of silently passing the turn
back and letting the user win against nobody. A hard error (no credential,
provider failure) still hands the turn back with the reason.runModelTurn
takes no abort signal, so a timed-out request is abandoned, not cancelled. -
The model turn's output budget was 16 tokens. On a reasoning-capable
model that budget covers the thinking pass, so the answer digit could be
truncated away before it was ever emitted — the turn then looked like a slow
model that skipped. Raised to 256; the visible reply is still one character. -
The status line read "Your turn — O" while the agent was thinking. It now
reads "Agent's turn — O".
v0.2.59
[0.2.59] — 2026-08-23
Fixed
-
/gamedrew its board as one 9-cell vertical column instead of a 3×3
grid. The board was a singleflexDirection: "column"box holding nine
bare text nodes — with no row boxes between the board and the cells, flex
put every cell on its own line. The tree is now built once inrenderTab
as three row boxes of three bordered cell boxes, andpaint()only
mutates the retained cell handles instead of clearing and re-adding all
nine nodes on every keypress. The cursor is a real highlight (focus border- highlight fill) rather than a swapped glyph, the winning line takes the
winner's colour, and legend/board/status are centred.
- highlight fill) rather than a swapped glyph, the winning line takes the
-
A model error during the game's turn was never visible.
applyModelMovewrote the message straight onto the status node and the
paint()immediately after overwrote it. The message now goes through a
noticestate thatpaint()owns and renders on its own line — the same
line that carries "agent is thinking…".
v0.2.58
[0.2.58] — 2026-08-23
Added
/game— tic-tac-toe vs the model in a TUI modal. A pure game core
plus a model move via an injectable, fail-closed provider factory; state
lives in the modal's own closure soEscminimizes without resetting and
reopening/gameresumes the same board. Available while the main agent
is busy, registered alongside the other agent-only slash commands.
Fixed
-
The interactive agent's runaway-tool-loop guard counted unique
tool-call signatures, conflating a big legitimate task with an actual
loop. A task with many DIFFERENT tool calls (e.g. a wide refactor) was
indistinguishable, under that metric, from real repetition, and hit the
same budget wall either way. Replaced the three unique-signature pools
(DEFAULT_MAX_TOOL_CALLS/_READ_/_NON_READ_) with a model-round-trip
cap (DEFAULT_MAX_ROUNDS,KERYX_AGENT_MAX_ROUNDS); the existing
per-signature attempt cap (MAX_ATTEMPTS_PER_HASH) remains the actual
repetition guard.spawn_subagentand wiki deep-enrich child budgets
migrated the same way. -
Untrusted web content could permanently block an unrelated tool call
turns later in the same session. Once anyweb_fetch/web_search
result came back untrusted, every later non-read tool call was refused
for the rest of the session, with no way back short of/new//clear—
including actions that had nothing to do with the tainted content. The
gate is now scoped to the turn the untrusted content appeared in: it
still blocks every later round within that same turn, but a following
user turn starts clean. -
External Slate-Adjacent Context (SAC) hands could get a workspace
auto-created for them at close. Flow 200's lazy resolve-or-create in
runWrapUpnow excludes external slates entirely — a hand that never
bound aworkspaceIdgets the unbound-candidate artifact, never a
created workspace. Internal session/flow wrap-ups keep the lazy resolve
(AC-38, flow 182).