- The API occasionally returns the same skill twice (built-in
shadow vs user copy, or a write/read race) which made the
duplicate-detector tag BOTH copies as the "recommended" keeper
(the find-skills card showing duplicate #1 twice). Loading now
filters out repeats by lowercased name before render.
- Reordered the per-skill kebab menu: Publish/Unpublish → Select
→ Edit → Test → Audit → Delete. Select previously sat at the
bottom; lifting it next to Publish puts the bulk-mode entry
point with the other bulk-style action.
- When Settings is expanded, the toggle bar's bottom radius/border
flattens and merges into the row below (zero gap, softer
top-border on the body) so the row visually reads as the toggle's
open-state content instead of an unrelated card below it.
- .research-query margin-top trimmed from 6px to 2px (lifts the
textarea ~4px closer to the description line above).
Auto handles 90%+ of cases — the row of category buttons was
visual noise on the main panel. Now:
- Removed the .research-category-row from above the textarea.
- Added a Format <select> inside Settings (next to Rounds) with
Auto / Product / Compare / How-to / Fact-check options. Default
is Auto, same as before.
- Updated all the JS that read .research-cat.active / data-cat to
read #research-category.value instead (_saveSettings, _readSettings,
_resetCategoryToAuto, _editJob, _restoreSavedSettings).
Same wire to the backend — settings.category still carries through.
Was rendering on its own row under "Multi-step web research with an
LLM-in-the-loop agent". Now appended to that same flex-wrap line as
"— past runs in Library, Research" so the header section stays one
visual block instead of two.
Was rendering on a second row below the "Past research" header,
inflating it to two rows. Now appended to the title span as a small
inline chip — "Past research — all in Library, Research" — keeping
the header at one row. Same click → close panel + open Library tab.
The capture-phase scroll listener was firing for scrolls anywhere
in the modal — including the Trending models list, which lives
inside the Direct Download fold body. Scrolling that list was
auto-folding the section that contains it.
Bail early if the scroll target is the fold body or a descendant —
the section only folds on scrolls in sibling scrollers (.cookbook-body,
.hwfit-list, .modal-content).
Each time the panel opens we pick a random entry from a list of 10
diverse research prompts (history, tech, food, science, fact-check,
how-to) so the textarea hint feels fresh and shows the breadth of
queries the tool handles instead of always nudging toward the same
Odysseus example.
- Removed standalone "Edit cmd & relaunch" — "Edit in serve panel"
renamed to "Edit & relaunch" and is now the single edit entry.
Tooltip notes that the raw cmd is still editable inside the panel.
- Tagged each item with a group (run / edit / endpoint / copy /
danger) and renderer inserts a thin divider whenever the group
changes, so the menu reads as visual blocks instead of one long
list.
- Header h2 inside the Active group now says "Active" (matches
the renamed tab) instead of "Running".
- Both context-menu Reconnect entries (the normal one and the
recover-from-vanished-process fix) say "Reconnect tmux" so the
user knows what the action actually does.
- Sibling cookbook-server-section-* blocks inside the Active group
get a top divider + 14px gap so transitions between server
groups (local / remote-host / etc) read clearly.
Previously the global GPU-toggle total was set once and never
overridden, so a first scan on the local 1-GPU container left
the Run-panel GPU button row stuck on GPU 0 even after switching
to a 4-GPU remote host. Now any scan returning a positive total
updates the binding; zero/missing values still don't clobber a
known-good count (no flicker during in-flight re-probes).
Mirrored the panel's runtime readiness note into a small chip
appended to the .memory-item-title at the top of the expanded
serve card. The in-panel note becomes a hidden source-of-truth.
This way the "vLLM ready on … : vLLM CLI: …; python package:
vllm 0.22.0" status sits inline with the model name where the
user is already looking, instead of buried below the toolbar row.
On initial render, compare total_ram_gb vs gpu_vram_gb — if RAM is
the larger pool, pre-select the RAM (count=0) button instead of the
max-GPU button. Boxes with more system RAM than VRAM (low-VRAM
GPU + lots of system memory, or CPU-only servers with a small
adapter) now open on the dominant pool.
New order: [Standard ▾] [Search ............] [Engine] [Quant] [Context]
so the two primary picks (type + free text) sit together at the
left, with the more advanced filters lined up to the right.
display:none toggle was instant and felt jarring during auto-fold/
auto-expand. Swapped to a CSS class `.is-folded` that transitions
max-height (0 ↔ 1200px) and opacity (0 ↔ 1) over ~280ms with ease,
so both manual chevron clicks and the scroll-driven toggles slide
in/out smoothly.
scroll handler now tracks per-target scrollTop via WeakMap. Downward
scroll on any scroller in the cookbook modal folds Direct Download;
scrolling back to top (scrollTop <= 0) unfolds it. Manual chevron
clicks still win — they persist to localStorage; auto-toggles
don't, so the user's last explicit pick survives reload.
IntersectionObserver missed the case because scrolling inside the
nested .hwfit-list (max-height:52vh own scroller) doesn't move the
header out of view at all. The user wants any downward scroll in
the scan/download area to fold Direct Download.
Switched to a capture-phase scroll listener on #cookbook-modal that
catches every scroll event from any nested scroller (.hwfit-list,
.cookbook-body, .modal-content). Folds only on downward scrolls so
scrolling back up doesn't keep re-folding.
The scroll listener on .cookbook-body never fired — the user is
likely scrolling inside the nested .hwfit-list (max-height:52vh)
which doesn't bubble to its parent. IntersectionObserver fires
whenever the Direct Download header crosses the viewport edge
regardless of which container moved.
Folds only when boundingClientRect.top < 0 (header pushed up past
the top) so modal close / detach doesn't trigger it.
Previous .modal-body / .cookbook-content lookup matched neither the
desktop scroller (.cookbook-body) nor the mobile one (#cookbook-modal
.modal-content), so the scroll listener was attached to document.body
and never fired. Walk up to whichever scroller actually exists.
Added a scroll listener on the parent .modal-body / cookbook-content
that folds the Direct Download body once its h2 header has scrolled
above the container's top edge. Frees the viewport for the Scan
section below while leaving the chevron clickable to expand again.
Auto-fold doesn't write to localStorage (only manual clicks do)
so the user's last explicit preference still wins on reload.
- Added a trending-up (market-up) SVG before the label, tinted
accent so the section reads as "what's hot".
- Chevron ▸ moved from the left to the right side of the toggle
row (still rotates via the existing CSS).
- Bumped the toggle row taller (26→34px) with 13px font + 18px
icon so the section header has more presence.
- Brain admin-card header rows get min-height:32px so cards with
toggles and cards without (Inject Skills) align.
- Cookbook Trending models tab nudged up 8px (top:-3 → -11).
- Removed the ↻ RESCAN button in hwfit toolbar; manual EDIT still
available and auto-probe runs on container restart.
- Reordered the toolbar so Audit sits left of Select (matches the
brain memories layout where bulk actions live before Select)
- Renamed "Audit all" → "Audit"
- Star icon in Audit now tinted with var(--accent, var(--red))
- Select button gets the same dot/X SVG swap used in brain
memories (dot in idle state, X when bulk-select mode is active)
Per user report — the tag's mode metadata coincided with a
500 error on agent mode (especially on mobile). Removing the
UI tag, the chat.js writes of metadata.mode, and the CSS pill
so agent mode posts work cleanly again.
Touches:
- chat.js: drop _sendMode capture + meta.mode writes (user + assistant)
- chatRenderer.js: roleTimestamp() back to a single (when) arg, drop
the .role-mode-tag append; updated three call sites
- style.css: dropped .role-mode-tag and .role-mode-agent rules
- Each input now has a sibling .email-field-prefix span (To / Cc /
Bcc / Subject) absolute-positioned at the left edge in the
accent color. Inputs get padding-left:44px (64px for Subject)
so typed text doesn't slide under the prefix.
- Placeholders shrink back to just the example so only the
prefix gets the accent color, not the example text.
- Cc toggle moved another 2px up (calc(50% + 4px) → calc(50% + 2px)).
- Removed the <label>To/Cc/Bcc/Subject</label> elements — they
doubled what the placeholder said.
- Placeholders now carry both the field name AND an example so an
empty input still tells the user what to type:
To recipient@example.com
Cc cc@example.com, example2
Bcc bcc@example.com
Subject
Adds a per-field X (24x24 SVG, opacity 0.4 → 1 + accent on hover)
absolute-positioned at the right edge of each Cc/Bcc field. Click
hides both rows, clears their inputs, and restores the Cc opener
on the To row. Inputs get padding-right:32px so the close button
doesn't overlap typed text.
Was `top: calc(50% + 4px)` which left the button 4px below the
true vertical center of the input — visibly misaligned. Dropped
the +4 offset so the toggle anchors at top:50% / translateY(-50%)
and tracks the input's center.
Also removed the redundant base rule's position:relative + top:2px
nudge — it was being overridden by the more-specific
.email-field .email-cc-toggle absolute positioning anyway.
- Renamed "Note (no timer)" → "Note".
- Clicking it now opens a small modal with a textarea + Save/Cancel.
- The typed text becomes the todo item; due_date is omitted so no
timer fires. Esc cancels; Cmd/Ctrl+Enter saves.
Re-adds the timer-less note path next to the time-based presets.
Picking it POSTs the same payload but omits due_date so the entry
lives in notes as a plain reply todo with no reminder firing.
Toast: "Reply note saved" instead of "Todo reminder set for …".
Was sticking on toggled-on state if the user closed the library
while in select-mode — reopening showed the Cancel/X toggle even
though no emails were selected. Force-reset state._selectMode and
state._selectedUids in openEmailLibrary so each open starts fresh.
Correct behavior:
1. Cached draft + first click → opens the cached reply
2. Cached draft + second click → clears the cache and opens the
Fast/Full + context menu so the user can request a fresh draft
3. No cache → opens the menu directly
Per-button shownOnce dataset tracks the first-click state so the
second click triggers the menu instead of replaying the cached
reply again.
- AI reply: removed the cached_ai_reply shortcut so clicking the
button always reopens the Fast/Full + context menu. Lets the user
ask for a fresh draft (with new steering) instead of being locked
into the cached one.
- .email-cc-toggle gets position:relative + top:2px so it
baseline-aligns with the To: field chips next to it in the
document email compose.
- Initial button: dot-in-circle SVG + "Select" label
- After click (select-mode on): X SVG + "Cancel" label + .active class
- Same SVG glyphs as memory.js so the two pages feel consistent.
Hooked into the toolbar Select toggle AND the bulk-bar Cancel button
so both reset the icon state.