Releases: Flare576/ei
v0.7.2 — Helping Help... Help!
What's New
UI orientation map — New users now get a spatial map of the interface at the end of onboarding, and it lives permanently in Menu → Help. Three zones: left panel (personas & rooms), top-right menu (your data & settings), chat tools (context, memory, images). Click any zone to expand what's in it. Sounds obvious in retrospect. Wasn't there before.
Instant tooltips on chat tool buttons — The ✦, 💡, 🎨, ✂️, and 🖼️ buttons now explain themselves immediately on hover. No more waiting two seconds for the browser to decide you were serious about wanting to know what the lightbulb does.
CYP rooms now tell you how extraction works — When you create or edit a Choose Your Path room, there's now an inline note explaining that Ei won't automatically scan for Topics and People in branching conversations — and that 💡 is how you trigger it when you're ready. This was a genuine gap. Glad it's closed.
Fixed
Status dot no longer gets clipped — The little colored indicator on persona avatars was being cut off by the avatar's circle. One CSS property. Took longer to notice than to fix.
Help modal stale content — The old Help modal listed keyboard shortcuts for a mouse-driven app and had a "you can always undo!" tip that wasn't true. Both gone. The modal now shows the same zone map as onboarding.
Stale "Traits" references — Human Data doesn't have a Traits tab anymore (we removed it a while back when it became clear we couldn't define it well enough to be useful). The web README, TUI README, and Ei's own system knowledge were still listing it. Cleaned up.
Image synthesis button disambiguation — The 🖼️ button on each message (generate from this message) and the 🖼️ button in the toolbar (synthesize from selected messages) were the same icon. The toolbar one is now 🎨. Your eyes will thank you.
Under the Hood
ZoneMapis a shared component — onboarding and Help modal both use the same source so they can't drift apart- Tooltip
alignprop handles edge-case clipping for rightmost buttons - E2E test selectors tightened up after tooltip DOM presence exposed some overly broad locators
v0.7.1
Fixed
- Zero-width space and other Unicode separator characters in OpenCode agent names were bypassing alias/display_name lookup in
persona_getByName, causing a new archived persona to be created on every import instead of matching the existing one. Stripped at both the lookup site and theresolveCanonicalAgententry point.
v0.7.0 — Room Renovation
What's New
CYP (Choose Your Path)
- Web: interactive ReactFlow tree showing the full conversation graph — node states (active, explored, masked), click to expand, jump navigation, markdown in expanded view
- TUI:
/contextopens an ASCII tree with BFS ordering, cursor follow, page navigation, and masked-state indicators;/activate [N]navigates by node number
FFA (Free For All)
- Per-room
context_window_hoursandcontext_boundarysettings now actually filter messages in the LLM prompt — rooms were previously unbounded - Web: full context management table in the Overview overlay — group delete with cascade count, status cycling (Default/Always/Never), root message protection
- TUI:
/contextopens a YAML editor with the same capabilities, including cascade-confirm delete
MAP (Messages Against Persona)
- Web: scoreboard table in the Overview overlay — round-by-round winner history with expandable message/verdict content, running win counts, status cycling on winner messages, score footer filtered to active room members
- TUI:
/contextopens a read-only ASCII scoreboard with score summary and keyboard scrolling
Human display name
- Your name now appears correctly in message attribution across 1:1 and room chats (web + TUI), quote management, and response prompts
Persona creator model picker (closes #53, hat tip to @tomsaleeba for being the first non-family user and immediately finding this 😄)
- Replaced the free-text model input in the persona creator with the same
ModelPickerdropdown used everywhere else — no more broken queues from mistyped provider names
Fixed
Alwaysmessages were being pruned during ceremony — marked to keep forever, silently rolled off anyway- FFA root message was incorrectly editable/deletable in context views
Under the Hood
sources[]added toDataItemBase— facts, topics, and people now track provenance (conversation/session origin); surfaces through MCP and CLIHandleOneShotJSONqueue path for image prompt synthesis- E2E coverage added for CYP, FFA, and MAP (web + TUI)
- Structural check: human display name must not be hardcoded in prompts or UI
v0.6.7 — Wonderful Web
Personas have faces now. Sort of. This release is all about making the web UI feel more personal — because a tool about personas that shows everyone as a grey circle was, in hindsight, a missed opportunity.
What's New
Persona Avatars
Pick an emoji or upload a photo. That's it, that's the feature.
Emoji shows in the sidebar, chat header, and room panels. If you upload an image, it gets center-cropped to 64×64 client-side before saving — no file upload, no server round-trip, just canvas magic. And if you do neither, it falls back to initials. Respectable.
Per-Persona Theming
Each persona can now have a preferred color theme. In a 1:1 chat, the whole message panel — bubbles, input area, the works — shifts to that persona's theme when they're active. In rooms, each persona's bubbles use their own theme colors, so you can actually tell who said what at a glance without reading the name.
The sidebar pill gets a colored left-border accent from the persona's theme color. Personas with no theme set get nothing — which is intentional. It makes you want to set one.
Custom themes you've defined show up in the preferred-theme dropdown. If you haven't made any yet, you'll see the eight built-in presets.
Modal UX
Clicking outside a modal now closes it. Specifically: mousedown on the backdrop followed by click on the backdrop. This means text-selecting content inside a modal and releasing the mouse outside it won't accidentally dismiss the whole thing. Small detail. Annoying until it's fixed.
Fixed
- Groups chip was bleeding into trait cards in the entity editor. It had no business being there. Gone.
- SliderControl was crashing when a trait had no
strengthvalue set. Undefined is a valid state; crashing is not. Fixed.
Under the Hood
PersonaAvataris a shared component now — sidebar, chat panel, and room panel all use it. One source of truth for avatar rendering logic.- Per-persona bubble theming is scoped via a
data-persona-themeattribute on the container. CSS custom properties do the rest. useOverlayClosehook handles themousedown+clickpattern for all overlay/modal components going forward.- E2E coverage: emoji picker, image upload tab, preferred theme selector, and the backdrop-click close behavior.
v0.6.6 — Role Models
Role Models
This one's about models — how Ei tracks them, displays them, and routes to them. Plus a fix that was quietly making extraction batches 5× smaller than configured.
What's New
Model usage stats in both UIs — token counts and call totals now show up in the TUI YAML editor (as a comment above each model) and in the web provider settings. Because knowing you burned 311.5K tokens on Haiku in a minute is genuinely useful information. Numbers are formatted with compact notation — 311.5K, 25.7M — because raw 311500 in a config comment is just rude.
model_id and thinking_budget exposed — both fields are now visible and editable in the TUI and web provider editors. You could set these before, just... not easily.
Optimistic lock in /me — if the state changed under you while you had the editor open, we skip the stale write instead of silently clobbering newer data. Niche, but the alternative was a real footgun.
Fixed
Extraction batches were 5× too small when using bare provider names — if your extraction_model was set to something like EG or RnP (just the provider name, no :model suffix), the token limit lookup silently fell through to the 8192 default. That floored to a 10K minimum, which worked out to 7,650-token batches. You configured 50K. You got 7,650. That math was wrong and now it isn't.
Auto-detected local LLM accounts were created incomplete — both TUI and web onboarding would detect a local LLM and create a provider account with no models array. /provider would say "no models configured." The state migration patched it on next restart, but that's a weird first-run experience. Now the account is born complete — a (default) model entry, GUID wired up, ready to go.
Under the Hood
- E2E test infrastructure: added
EI_E2E_MODEbitfield for environment-dependent test seams. Bit 1 skips local LLM auto-detect so the no-provider test is deterministic regardless of whether LM Studio is running on the host. Bit 2 is reserved. It's a bitfield because past-us has been here before. - Fixed parallel flakiness in
/megroup YAML tests.
v0.6.5 — TUI Touchup
What's New
TUI got some love. This is the "TUI Touchup" release — a bunch of things that were slightly annoying are now slightly less annoying.
/help is actually helpful now
The old /h was a wall of text. Every command, dumped in a flat list, hoping you'd find what you needed by vibes.
New version: grouped two-column layout. Keybindings + Core on the left, Persona + Rooms + Extended on the right. Compact enough to actually fit on screen. And if you need the full reference, press m — it opens a proper man page in $PAGER (yes, your $PAGER, whatever you've set it to).
/me can create things now
This was embarrassing. You could edit and delete facts, topics, and people from the TUI. You could not create them. The web app had buttons. The TUI had ¯\_(ツ)_/¯.
Fixed. Each section now includes a commented stub. Uncomment it, fill it in, save — done. No UUID required, one gets generated for you.
Also added filtering while I was in there:
/me fact coffee— shows only facts whose name contains "coffee"/me fact new— opens with just the stub, no existing data in the way- Singular aliases work:
fact,topic,personall accepted
Duration strings in YAML editors
heartbeat_delay_ms: 1800000 is not a number a human should have to read or write. It's now heartbeat_delay_ms: 30m. Same for all _ms fields in /settings and /d. Accepts s, m, h, d, w. Round-trips correctly.
context_window_hours in /d now always shows up (was silently absent when unset). null means "inherit from global settings" — not a snapshot of whatever the default was when you created the persona.
--version flag
ei --version # 0.6.5
ei version # also works
ei -v # also works
Ghost frame / cursor artifact on editor close
After using the app for a while, closing $EDITOR would sometimes leave a painted buffer frame and the cursor stuck at the bottom of the window. Tracked it down to a double-render race — resume() already schedules a render internally, and we were queuing a second one via queueMicrotask that fought with it. Removed the extra call. Seems solid.
Error overlays after $EDITOR weren't showing
YAML parse errors after editing would log correctly but the "Re-edit?" modal would be invisible until something else triggered a repaint (like pressing Ctrl+C). SolidJS needed a microtask to flush the signal before OpenTUI painted. Fixed in showOverlay — applies to all editor-based commands, not just /me.
/editor command clears input on exit
/e or /editor opens $EDITOR with your current input. When you close it — whether you saved something, saved nothing, or hit abort — the input field now clears. Previously it left /editor sitting in the box, which was useless.
Fixed
- Core: fixed a bug where quote links weren't cleaned up when the target was already merged via dedup
- Core: pass resolved record from match handler to update queue, skipping a redundant GUID re-lookup that could fail
- Topic validate phase: post-create near-duplicate detection now runs after new topics are added
Under the Hood
v0.6.4
Fixed
-
Partial model responses no longer silently drop valid updates or cause retry storms. This is the real fix for a bug that's been present since v0.2.0.
When Haiku correctly omits unchanged fields from a response — "the name is fine, I only have a description update" — the old handlers either silently dropped the entire update (pre-v0.6.3 behavior, when
console.error+returnwas used) or threw and retried indefinitely (v0.6.3, when we added the no-silent-drop invariant). Neither was right.The resolution chain for each field is now explicit:
name→ model value → existing record → candidate from scan → throw if new itemdescription→ model string → existing record → candidate from scan → skip if updating, throw if new itemsentiment→ model value → existing record →0(neutral) if new item
Boolean
description: true(Haiku signaling "yes, there's a description" without providing one) now falls back to the existing record value instead of being stored as the literal string"true".New items still require a description — you can't create a record with nothing to say about it.
Tests
- Added a parameterized contract test suite (
UPDATE_HANDLERS) that runs every human data update handler against partial model responses. Description-only, sentiment-only, boolean description, missing fields — all cases covered. Adding a new update handler requires an explicit entry inUPDATE_HANDLERS, making the contract opt-in and visible.
v0.6.3
Fixed
-
handlePersonUpdatenow handles missing or booleandescription/sentiment. Same Haiku pattern as the topic fix in v0.6.1 — model omits fields it has no reason to change, handler threw. Now falls back to the existing person record's values before validating.descriptionalso gets atypeofcheck to reject booleantruethat Haiku occasionally returns instead of actual text. -
handleFactFindrejects non-string fact values. Added atypeofguard so boolean or null values from the model get skipped with a log instead of potentially being stored.
Under the Hood
- Added structural check 7: enforces that extraction update handlers use
typeof result.description === 'string'before accepting a description value. Catches this class of bug at CI time going forward.
v0.6.2
Fixed
handleTopicUpdatenow survives a new topic where the model omitsname. On the create path, the candidate name lived in the prompt text but wasn't stored inrequest.data— so when the model correctly decided "this name is fine, no need to repeat it," the handler had nothing to fall back on and threw. NowcandidateNamerides along in the request so it's available as the final fallback. Priority chain: model-provided name → existing topic name → original candidate name.
Under the Hood
- Fixed the
provider-editorE2E test so it no longer fails when LM Studio is running on port 1234. The test was accidentally validating environment state instead of the feature. Both describe blocks now use a pre-seeded provider checkpoint and go straight to Ready.
v0.6.1
What's New
/meonly saves what you touched. Before this, saving the human data editor would upsert every fact, topic, and person — bumpinglast_updatedon all of them even if you changed one field. Now it diffs your edits against the originals and only writes records that actually changed. The notification count reflects real writes, not "everything that came back through the parser."
Fixed
-
validated_dateis now read-only in/me. It was sitting there as an editable field, which caused a fun bug: every time you opened/me, the parser would auto-stamp a freshvalidated_dateon all your facts and people — making them look "changed" even if you hadn't touched anything. Now it shows up in the YAML as# [read-only]alongside the other system timestamps, and the diff logic ignores it entirely. -
handleTopicUpdateno longer chokes when the model omitsname. The system prompt says "only update name for clarification" and apparently Haiku took that seriously — it would return a perfectly good description and sentiment update without repeating a name it had no reason to change. The handler requirednameunconditionally and threw, retrying six times to the same result. Fix: fall back to the existing topic name when the model omits it. New topics still require both fields. -
Prompt instruction updated to match. The old "ALWAYS include name, description, and sentiment" was contradicting "only update name for clarification or further specificity." Fixed to: omit
nameto keep the existing one, always includedescriptionandsentimentwhen returning a record.
Under the Hood
yaml-serializers.tswas pushing 1,500 lines. Split into 9 focused domain files (yaml-human,yaml-persona,yaml-settings,yaml-provider,yaml-quotes,yaml-context,yaml-queue,yaml-toolkit,yaml-shared). The old file is now a barrel re-export, so nothing broke.