changelog
What's new in each release of crystl.
2.102.0
- The welcome tour now covers the copy bar and quest heroes/parties, and links straight to the iPhone companion app.
- Welcome tour cards auto-size to their text, so longer tips are never clipped.
- Quest commands (quest_msg, quest_heartbeat, and friends) no longer come up missing when starting a fresh quest right after updating Crystl.
2.101.0
- Configurable integration targets: point a gem's isolated shards and sealed quests at any branch (a release or feature line), not just main. Set a global default in Settings → Worktrees, override it per gem in the gem's worktrees tab, or use the new
crystl worktree targetCLI. Merges go to the target, and isolated shards now fork from it too. - Heads-up: isolated shards now fork from the gem's integration target (the repository default branch by default) instead of your current checkout. Set a gem's target to "current branch" to keep the old behavior.
- Fixed the frozen "thinking" spinner: a self-healing repaint watchdog ends the occasional stacked or frozen spinner during long agent streams, so you no longer have to scroll to unstick it.
- Cleaner table redraws on resize: better dedup of stale table copies.
- A real Settings screen with a default-view preference and a quest-tab toggle, shard detail now opens at the latest message, plus pairing-screen polish.
- A large batch of gem-settings panel fixes: the new worktrees tab, panel positioning, scroll behavior, and spacing.
2.100.2
- Tables no longer shatter on window resize: stale table frames, border skeletons, empty-cell frames, wrapped-cell fragments, and mixed-width rows are all cleaned from scrollback after narrow-to-wide drags
- Table rows that only ever existed at one width are preserved intact rather than deleted, so no content is ever lost during cleanup
2.100.1
- Hero editor hints hug their fields
- Hero editor fits laptop screens; AGENT hint no longer overlaps MODEL label
- Path browser can ascend to filesystem root — network mounts reachable
- Height-only grows never arm the reveal mask
- Height-only grow masks only the revealed top band; copy bar dips 20px into bottom chrome
- Copy bar carves the terminal content area instead of resizing the window
2.100.0
- Rapid double shard create no longer routes two agents into one worktree
- Deferred resize — grid + winsize commit once on settle
- Env-gated /debug-rows route — structured scrollback dump (glue instrumentation)
- Adopt stale-overhang invalidation + presenter mismatch contract (core c63fa97)
- ~40-column floors for window + split panes; document the winsize contract
- Adopt deep-centered hanging indent (terminal-core efb9e8b)
- Adopt hanging-indent reflow (terminal-core 7e083c0); promote narrow-reflow guard
2.99.0
- Deliver party messages to the quest's gem, not selectedProject
- Sealed heroes' replies landed in a worktree-local bus nobody watches
2.98.2
- Rename shards without losing their identity. Shards now have stable internal IDs plus editable display names, so you can keep human-friendly labels without breaking session restore, history, formations, CLI targeting, or mobile prompts.
- More reliable shard targeting. Bridge and CLI commands resolve stable IDs first, then unique display labels, and reject ambiguous duplicate names instead of silently routing to the wrong shard.
- Side quests stay connected to the right agents. Side-quest routing now uses hidden stable route names while showing the readable shard labels in the picker and turns panel.
- History and restore polish. Reopened shards keep their original session identity, worker lineage resolves by stable shard ID, and the history viewer shows current custom shard names where possible while preserving older original names.
- Agent safety fixes. Option+Deny now asks before aborting a whole session, Codex permission decisions use the required nested payload shape, resume prompts are agent-neutral, and PTY sizing is reasserted after spawn so TUIs do not start squished.
2.98.1
- Security hardening for license validation. Tightened how Guild membership is enforced so it can't be bypassed in shipped builds. Recommended update for everyone.
2.98.0
- Antigravity is now a first-class agent. Google's
agy(the Gemini CLI's successor) can be picked for heroes and quest parties with full model + persona support, and launches with the right binary. It replaces the sunset Gemini CLI in the agent picker. - Resurrect brings back Codex and Antigravity conversations, not just Claude. Reopen a recently-closed shard (Cmd+Shift+T) and it resumes the actual session —
codex resume/agy --conversation— instead of starting the agent fresh. - History and resurrect now track each shard by instance. Two shards that share a crystal name no longer show or resume each other's conversation — each resolves to its own session exactly.
- More reliable agent transcripts. Fixed a case where launching crystl from inside another agent session could stop shard agents from saving their history, which broke history, resurrect, and resume.
2.97.1
- Chat dock fixes — reliably shows the conversation now (fixed a session-resolution bug that could leave it empty), no longer ghosts over the terminal after opening Settings, and has a close ✕ in the top-right.
crystl historyshows token & model metadata — each turn carries its model + token usage + duration, with a session summary (tokens, tool calls, models, active time) on top;--jsonemits the full metadata. Useful for judging an agent's cost and context.- Drag-to-scroll selection — dragging a text selection past the top or bottom edge now auto-scrolls and extends it.
- Everyone lands on cavrn — anyone stranded on the retired SwiftTerm renderer is moved to cavrn's Metal GPU terminal, with the announcement card and a "learn more" link to the docs.
- Fresh-start launch — hold Option while opening Crystl to start with no restored gems.
- Copy-table ⋯ — now detects box-drawing tables and anchors just to the right of the table.
2.97.0
- Remove crystl block command + agent instructions
- Revert desktop chat-view reuse (empty-dock regression)
- Pin box-drawing tables through the hover-copy hit mapping
- Hover-⋯ copy: scan viewport with unified TableDetector
- Detect box-drawing tables via a shared TableDetector core
- Render the VM's stable-id entries in the conversation list
- Stable-id conversation entries + no-op refetch skip for the phone
- Pin chat view reuse with DEBUG measure/build counters
- Reuse worker-thread bubbles + cache measured sizes in ChatThreadView
- Reuse chat dock row views across streaming updates
- Add ChatListDiffer: pure prefix diff for chat view reuse
- Bump terminal-core pin to 494214f (live tables clip, not scatter, on narrow)
- Bump terminal-core pin to 0acfa47 (markdown table rows clip, not scatter, on narrow)
- Add detected-table hover ⋯ copy (raw / CSV / JSON) on the Prism surface
- Add CrystlKit markdown-table detector + DetectedTable model
- Detected-table copy + mobile render (parse what Claude draws)
- Bump terminal-core pin to 0646633 (passive blocks — let Claude draw)
- Prism harness: block scenario asserts the passive drawn-inline model
- Prism adapter: keep block regions in frames, region-based hover lookup
- crystl block: emit the full drawn fallback everywhere, drop c=1
- Spec PIVOT 2: let Claude draw — blocks passive, hover ⋯ as backup
- Block anchor hover ⋯ actions menu (copy as markdown/tsv/json + view)
- Bump terminal-core pin to c9bf51e (reflow root-cause fixes)
- Bump terminal-core pin to b442e50 (synthetic box-drawing glyphs)
- Spec pivot: blocks as hover ⋯ copy/download/share, not auto-open viewer
- Bump terminal-core pin to 530d57d (compact anchor persists across repaints)
- Update anchor byte expectations for the c=1 compact param
- Pin terminal-core 625a65a (accordion compact projection) + accordion viewer
- Update block CLI snippet copy for the accordion viewer model
- Accordion block viewer: one-row anchor + native viewer panel
- Quiet native block fallback: anchor row + spacer footprint
- Bump terminal-core pin to e1a8f4f
- Bump terminal-core pin to b546555 (tmux-anchored narrow reflow)
- Bump terminal-core pin to 0694602 (run/row-sequence reprint dedup)
- Bump terminal-core pin to ae73c59 (selection row-range clamp crash fix)
- Bump terminal-core pin to 57e3a03 (streamed-reprint dedup)
- Bump terminal-core pin to a70b6b9 (resize-reprint frame dedup)
- Bump terminal-core pin to 1561660 (in-place TUI replay around closed blocks)
- Bump terminal-core pin to f5e06ca (frozen-scrollback block-tag fix)
- Keep top-clipped block regions native in Prism scrolled viewport
- Bump terminal-core pin to 36778ac (top-clipped block rowOffset fix)
- Bump terminal-core pin to 5ba8791 (soft-wrapped table fallback residue fix)
- Fix xterm resize during async writes
- Add glass background SGR rewriter for near-black badge backgrounds
- Trim CLAUDE.md: tighten Agent Support intro + obsolete SwiftTerm aside
- Trim CLAUDE.md: collapse Typography token enumeration
- Trim CLAUDE.md: condense the file map to non-obvious entry points
- Trim CLAUDE.md: move glass-readability runbook to swiftterm-notes.md
- Trim CLAUDE.md: move Bridge API endpoint catalog to docs/bridge-api.md
- Fix Prism showing stale content after a shard shrinks below its content height then grows back (#55)
- Bump terminal-core pin to df3bc8d1 (Prism table-fallback-residue fix) (#53)
- Fix Prism live-resize cadence
- Reconcile settings cleanup with cavrn-default flip
- Bump terminal-core pin to ba95ae5 (block persistence + chrome extent + CRLF capture fix)
- One-time "say hello to cavrn" card for existing users
- Simplify TERMINAL RENDERING to cavrn default + xterm fallback
- Make cavrn (Prism) the default terminal surface
- Clean up terminal rendering settings
- Pin PTY == engine == layout width in the harness past launch
- Seat hidden stacked shards when the workbench drawer opens
2.96.2
- Fixed tables and wrapped lines getting permanently mangled when the window is narrowed while an agent is still streaming output. The row under the cursor was being cut short during the resize and never recovered; it now reflows like every other line, so mid-stream resizes are safe.
2.96.1
- Fixed a quest party starting with helper scripts installed for only one hero. When you launched a party, only one hero got its quest_* toolkit (quest_msg, quest_heartbeat, quest_task, quest_summary, quest_handoff, quest_claim) — the other heroes were left without them, and their PATH could point at an unrelated project. Every hero in the party now gets its full toolkit provisioned into the correct per-shard folder.
2.96.0
- Fixed quest agents going silent after you clear the chat history. Clearing chat used to move the quest helper scripts (quest_msg, quest_heartbeat, and the rest) out from under running quest shards, so agents could no longer post to the party until they rebuilt the scripts themselves. crystl now reinstalls them the moment you clear, so the party bus keeps working.
- 'crystl sidequest start' can now pair shards across different gems. '--gem' is optional, and each endpoint can name its own gem as '<gem>/<shard>', for example: crystl sidequest start --a web/garnet --b app/citrine. A bare shard name with no --gem resolves across every open gem.
2.95.0
- Gem settings now opens right next to the gem you clicked, and you can drag the panel anywhere.
- Gem settings scrolls internally when it gets tall instead of running off the bottom of the screen, on both the identity and agents tabs. The enable toggles on the right no longer get clipped.
- The side quest shard picker now lists every open shard on both sides, including plain shells, with a count so you can always find and scroll to the one you want.
2.94.1
- Fixed an occasional black frame when opening or switching terminal tabs — a safety timer now clears the overlay if the terminal's redraw acknowledgement is delayed.
2.94.0
- Lead-color dots — a worker spawned by an anointed orchestrator shows a small dot in its lead's crystal color, so you can see at a glance which orchestrator a worker belongs to and group siblings by color.
- Orchestrator visibility — the bridge/API and CLI now surface which shard is the orchestrator and, for a worker, its lead's name (
isOrchestrator/leadName). - Side-quest CLI —
crystl sidequest start/end/statusplus bridge routes, so you can spin up and track a focused side conversation from the terminal or phone. - Hover-only close — the shard-bar close × now appears only on the pill you're hovering, keeping the bar uncluttered.
- Restored Codex shards keep their agent — a Codex shard no longer comes back as Claude after a restart.
- Thinking-doubling / overlap — the terminal now refits when bottom chrome changes its height, fixing stacked spinner frames and separator rules drawn through text during heavy agent churn.
- Retired the auto-start-Claude setting (a default agent launched in every new shard); new shards start at your own shell.
2.93.0
- Agents are now time-aware: every shard gets the current time (CRYSTL_NOW), and the workbench and quest streams timestamp when items and messages happen
- crystl shards / status now show how long each agent has been working or idle and when it last produced output — so an orchestrator can spot a stuck fan-out worker at a glance
- More readable dimmed and secondary terminal text on the glass background
2.92.4
- Improved readability of dimmed and secondary terminal text on the glass background
2.92.3
- Much faster startup with many shards — the shard you're looking at loads first, and background terminals no longer pile up in memory
- Fixed faded grey typed input in the terminal — it now renders clearly readable
- Claim a task by adding @name to its line — shows a coloured pill you can clear with a click
- Cleaner spacing between active task cards
2.92.2
- Switching back to a shard no longer flashes blank — its last screen shows instantly while the live terminal catches up
- Fixed the terminal occasionally not repainting after the copy bar opens
2.92.1
- Fixed terminal text overlapping or garbling when opening the workbench drawer or chat dock
- Fixed the workbench board rendering garbled when its file used Windows-style line endings
- The workbench drawer now auto-opens only when items are added, not on edits or check-offs
2.92.0
- Lift dim text to readable contrast in xterm shards
- Refit xterm terminal when the backlog drawer toggles
- Send newline on Shift+Enter in xterm shards
- Stack side-quest picker columns vertically
- Filter side-quest picker to agent shards
2.91.1
- Improved remote shard readiness checks so SSH-backed sessions wait for the correct shell state before continuing.
- Tightened bridge routing, transcript handling, and clean-port test coverage for safer release validation.
- Fixed bottom dock layout clamping and refreshed several CLI/doctor/resurrect paths.
2.91.0
- Added
crystl gauntletto launch a release-readiness crew with two Seekers, one Monk, and one Scribe. - Solo hero shards now accept opening tasks with
--prompt/--task, includingcrystl shard create --hero ... --prompt .... - Updated the agent-facing CLI docs so spawned agents know how to use gauntlet and hero task prompts.
2.90.1
- Fixed screenshot and copy bars overlapping or staying offset after chat, sidebar, and backlog layout changes.
- Fixed xterm terminal colors so Claude and ANSI-colored output render consistently with SwiftTerm.
- Prevented inherited no-color tooling settings from making new Claude sessions render without color.
2.90.0
- New
crystl doctorcommand checks CLI install, bridge connectivity, and hook wiring before debugging approval or notification issues. - New
crystl resurrectcommand can list and restore recently closed local shards from the command line. - Expanded CLI automation for Workbench tasks, event streams, wait conditions, AskUser prompts, and SSH bridge routing.
- Improved remote SSH support for Codex shards, including notification and hook routing.
- Hardened shard resurrection so closed shards recover more reliably with their name, color, isolation state, and agent session.
2.89.0
- xterm is now the default terminal renderer, with SwiftTerm still available as a fallback.
- Terminal rendering settings now clearly separate xterm WebGL from SwiftTerm Metal GPU rendering.
- Added a terminal font picker for installed monospaced fonts, including Nerd Fonts installed through Font Book.
- Added a terminal renderer benchmark harness for comparing SwiftTerm Metal, SwiftTerm CoreText, xterm canvas, and xterm WebGL.
2.88.1
- Side quest: the shard picker now shows each shard's full name and colors it by its crystal, so you can tell exactly which two shards you're connecting. Long names scroll into view on hover.
- Fixed the command-line-tool description getting clipped behind the install status.
2.88.0
- New default terminal engine: a faster, more reliable xterm.js renderer that fixes the resize glyph-scatter and redraw glitches.
- Your existing shards are unaffected. New shards use the new engine automatically.
- Prefer the old engine? Flip back to SwiftTerm anytime in Settings > General > Terminal Engine.
- Plus 30+ terminal improvements under the hood: clipboard and paste hardening, click-to-open, file and image drop, split-pane focus, crash recovery, and hibernation for hidden shards.
2.87.0
- Approval, question, and notification panels no longer steal focus to a background agent. Your typing stays where you are, even during fan-out.
- The side-quest panel now shows its shard picker (it was being cut off).
- The turns button no longer overlaps the working directory path or long URLs.
- Push-based orchestration. Fanned-out worker shards notify their orchestrator the moment they finish or get blocked, so the lead never has to poll.
2.86.1
- Fixed the castle marker so it only appears after the anoint briefing is actually delivered to an agent.
- Cleared legacy false-positive anoint state on restart so plain shards do not keep the castle icon.
2.86.0
- Multi-agent chat (Phase 2): click a worker in the chat dock's workers tab to read its full lead↔worker thread inline.
- Anoint an orchestrator: the new "anoint" button (crown) sets a shard up to coordinate workers; it fires the briefing straight into the agent and confirms inline.
- Orchestrator shards now wear a castle marker, and the workers tab shows live worker status — both survive an app restart (worker lineage now persists).
- The start panel always fits on screen (the start button can no longer hide below the Dock), with a "local heroes" disclosure and a draggable panel.
- A clearer inline "continue / start fresh" resume choice replaces the old second window, and the misplaced non-quest shard restore is gone.
- The "end quest" dialog now guides the decision — it shows each sealed hero's branch state and offers "end & keep" vs "end & close", with the explanation tracking the button you hover.
- The pulsing quest-recall tile in the rail now comes back after an app restart instead of disappearing.
- Security & reliability hardening: stricter shell-escaping on shard cwd, quest hook input validation, image-upload path confinement, decision validation on the legacy bridge route, and honest failure reporting when an API key can't be saved to the Keychain.
2.85.1
- Fixed a memory leak — closing a shard or gem now frees the agent's memory. Previously an agent process could survive close and accumulate over a long work session.
- Agents can no longer override your gem's approval setting. If you set a gem to auto-approve, a fanned-out worker won't silently re-introduce the prompts you opted out of.
- The shard bar no longer fights your scroll — with many shards open, a "thinking" shard no longer snaps the bar back to itself, so off-screen shards stay reachable.
- Custom-named shards always get a color instead of an occasional colorless label.
crystl wait awaiting|idle— block until a fanned-out worker parks on a prompt or finishes its turn (for agent orchestration). The chat workers tab now reads "● W/N active".
2.85.0
- New — multi-agent orchestration view in the chat dock. When an agent fans out workers (
crystl shard create), the chat dock (Cmd+Y) surfaces them in a workers tab: a live, recency-sorted roster (status · activity · unread) with filters. Zero workers = exactly today's 1:1 chat, so it only appears when you fan out. - Workers no longer stall invisibly.
crystl shardsandcrystl statusnow flag a worker parked on an in-terminal approval prompt with⏸ awaiting input(and over the live event stream) — a blocked fan-out worker is visible instead of silently stuck. - Fixed: the chat dock could show the wrong worker's conversation when several non-isolated agents ran in one project — each shard now resolves to its own session.
- Fixed: chat answers could lose chunks — a big reply followed immediately by a tool call no longer drops text from the dock.
- CLI:
crystl closenow works on gem names with spaces, and reopening an already-open gem focuses it instead of duplicating the tab. - Quest hygiene: per-shard quest helper directories are cleaned up on close instead of piling up.
2.84.1
- Fixed a regression from 2.84.0 where resuming a normal (non-quest) session could inject a stray "re-read the recent quest chat" prompt. Resume now only adds the quest continuation prompt for actual quest heroes.
2.84.0
- Fixed a freeze where Crystl could hang for up to a minute. The agent process scan and git-repo checks no longer run on the main thread, so heavy sessions stay responsive.
- Fixed resuming a quest. Reopening a quest now restarts each hero's Claude session with a continuation prompt instead of failing to come back.
- Fixed Return not always submitting in the chat dock. Typed messages now reliably send (bracketed-paste + retried Enter), including multi-line.
- Fixed the chat dock dropping an agent's answer (it would flash in then vanish on the working→idle edge), plus a related case where one shard's conversation could linger after switching shards.
- Hardened the gem-sidebar layout so the terminal stays correctly sized below the shards bar, split panes included.
2.83.0
- A new insert button brings your facet prompts straight into the chat composer, grouped by slot in a compact, scrollable list. Pick one to stage it for editing, or have it send right away.
- A typing indicator now shows while your agent is working, matching the phone.
- More reliable agent spawning: a first prompt that contains apostrophes or quotes no longer breaks a new shard's launch.
- The turns-left indicator now sits centered under the terminal and no longer overlaps long file paths or URLs.
2.82.0
- Heroes now come from crystl.dev. Fresh installs ship with the 15 core preset heroes (no download), and Settings → Heroes → "sync from crystl.dev" pulls the full roster on demand. crystl.dev is the source of truth; each hero carries its agent and model.
- New "end quest" button right in the quest panel header — end a running quest in one click (heroes return to normal solo shards). Also available as
crystl quest endand over the bridge. - Quest party roster only shows actual heroes now. A regular shard that happened to be open in the gem no longer gets pulled into the party.
- Hero file claims moved to the Activity feed. The roster stays clean (name, role, context health, status); who-locked-which-file now reads as activity.
- Clicking a DM channel or party member while on the Activity tab now switches you back to chat so you actually see the conversation.
- Add items to a specific section with a per-section "+ item" button (always visible). Section titles type in caps to match how they render. The panel title is larger so it outranks section headers.
- Quest panel buttons unified to a single bordered "turns button" style with consistent corners; "open quest" stays a pill.
2.81.0
- Pin the chat composer to the bottom of the dock column
- Start the copy bar right of the chat dock column
- Keep the chat composer fixed when the screenshot bar toggles
- Make rendered links clickable in the chat dock
- Keep the turns button clear of the cwd path label
- Syntax-tint fenced code blocks in the chat dock
- Render horizontal rules in the chat-dock markdown
- Render blockquotes in the chat-dock markdown
- Accept image drops into the chat-dock composer
- Add a gap between the screenshot bar and the chat composer
- Render markdown in chat messages instead of raw text
- Seat chat dock in the terminal content band so the composer clears the screenshot bar
- Coalesce re-entrant drawer rebuild to stop doubled rows
- Clear working state on StopFailure, not just Stop
- Never steal focus on programmatic shard create
- Submit the composer on Return via keyDown
- Correct shell quoting in quest_msg helper guard
- Abort quest_msg if _quest_helper.sh missing; copy helper before producer
- Drive the chat dock off real-time events, not a 2s poll
2.80.5
- Make the composer reliably grab the caret
2.80.4
- Show checkmark on the View-menu toggle-chat item
- Tear down chat dock when its shard/gem closes out from under it
- Re-target chat dock synchronously on shard/gem switch
- Close stale background default shard on remote isolated create
- Quest tile renders white and shimmers while the quest is live
- Desktop chat-mode dock for agent conversations
2.80.3
- Inset the pinned creation cluster from the window edge
- Let the panel go behind other windows (drop floating level)
- Shorten message input to the chat column, not full window width
- Clamp party roster scroll region above the input bar
- Stop quest/isolation labels collapsing in sidebar (stacked) mode
- Keep Isolation/quest labels from collapsing at high shard counts
- Scroll party roster so large parties don't spill off-screen
2.80.2
- Make Quest popup draggable by its top bar
- Use defaultBranch for advisory diff refs
- Refuse remote isolated restore on worktree-create failure
- Surface branch-reattach failure distinctly from generic failure
- ShellEscape the local quest temp-file path
- PATH floor so launchd/Finder launches can spawn a shell
- Confine POST /gems open-path to $HOME
- Insert
--before host in ssh terminal-send sites - Refuse merge/rebase when primary checkout is off the default branch
- Insert
--before ssh host in every RemoteSession argv - Reassert token file mode 0600 on every rewrite
- Never degrade a failed isolated create onto the primary checkout
- Validate OSC 7771 ssh host/control-path before storing
- Constant-time bearer-token compare
- Add scripts/verify.sh — one-command renderer/engine gate
- SwiftTermEngine adapter + TerminalRenderHooks (sole backend)
- Define TerminalEngine protocol + EngineCursor (CrystlKit)
- Read-only DEC mode 2026 sync instrumentation (gated)
- Schedule a draw on sync-frame edges so the widened dirty range is consumed
2.80.1
- Show pointing-hand cursor over the Copy button
- Wordmark → brand serif logo lockup (splash + pairing)
- Self-reconcile the orchestrate prompt so improvements reach all users
2.80.0
- Update app icon to the new gradient-crystal mark
- Free the iPhone app over LAN; keep "from anywhere" Guild (Apple 3.1.1)
- Default bug-report reply email to the licensed account
- Persist gem/shard layout on every change so restore survives crashes
- Full-rebuild on shard re-show (belt-and-suspenders)
- Tighten hidden-shard guard (drop alpha clause, add re-show repaint)
- Don't draw hidden/stacked shards (Metal bleed through glass)
- Apply Crystl renderer patches as source
- SwiftTerm v1.12.0 source in-tree (pristine upstream)
- Crystl render --dump-cells — offline bytes→grid dump
- Headless bytes→grid render seam for the agent-first harness
- Vary injected CLI snippet intro by build identity
2.79.0
- Draw the handle brighten in the view itself
- Pull-tab signal is a slow brighten, not a faint sweep
- Make pull-tab shimmer sweep vertically
- Arm the file watch before the workbench file exists
- Prevent pull-tab shimmer from double-stacking
- Close orphaned default shard on background isolated create
- White quest tile that pulses + shines while agents work
- Don't steal focus on background/CLI shard creation
- Shimmer the pull-tab handle when an agent adds items
- Make the quest chat window closable
- Replace confusing goal placeholder with system-voice orientation
2.78.0
- Default to Claude Code's classic renderer in Crystl
- Raise scrollback to 2000 lines
- Align question text's left edge with the header
- Stop the layout pass from restretching the panel to 360pt
- Auto-dismiss question/notification cards a beat after "show"
- Don't let a stale questAgents entry override the live hero
- Make the agent field a plain text box that reliably saves
- Inject persona for custom quest-party agents + agent-field hint
- Open-ended agents for heroes and quest roles
- Accept any CLI as a custom spawn agent
- Require movement before a library row starts a drag
- Skip the bare-shell guard on remote shards
- Don't touch existing users' bar when seeding orchestrate
- Guard orchestrate against a bare-shell paste
- Orchestrate-specific upsell instead of the generic Guild pitch
- Drag-reorder slots & library, primary treatment, view button
- Add Guild-gated orchestrate facet
2.77.3
- Stop the focus-report storm that froze focus-reporting TUIs
- Open links async so click-to-open can't strand keyboard focus
2.77.2
- Don't carry a text selection across tabs
- Revert "fix(copy-bar): make only the active tab chip read as selected"
- Make only the active tab chip read as selected
- Keep selected text readable with a tinted selection
- Use overlay scrollers so text isn't wrapped short by the scroller gutter
- Show a pointing-hand cursor over the Copy button
- Reclaim terminal focus on click so the caret isn't stranded
- Stop a background TUI shard from stealing the window's scroll
2.77.1
- Route a background-gem push to that gem, not the foreground bar
- Auto-hide the scroller so it stops overlapping the Copy button
- Make the copy bar per gem instead of window-global
- Don't report a TUI's dim ghost-suggestion as typed input
- Give the copy button a solid background
- Hand keyboard focus back to the terminal on Esc
2.77.0
- Auto-close a delegated task when its summary lands
- Collapse chat/tasks/summaries into Chat + Activity
- Keep the quest window from vanishing + always-recallable chat
- Keep sidebar health bars up across transient agent-detection misses
- Show the active party name in the quest window header
- Move file-claim noise out of chat into the sidebar
- Stop blanking hero roles in the chat sidebar
2.76.2
- Make crystl copy free on every tier
- Editable docked copy bar with shard-colored tabs
- Crystl party list/create/delete
- Reveal hero stat card on click, not hover
- Committable named party templates via "create local party"
- Flip dropdown above the bar when it would fall off-screen
2.76.1
- Show custom heroes in the solo summon picker
2.76.0
- A party new to a directory starts on a clean chat
- Only prompt "continue?" when relaunching the party that owns the chat
- Dedup-proof the add-member dropdown + drop picker diagnostics
- Party popup deduped duplicate-titled parties, breaking selection
- Select popup after add-to-hierarchy + prune orphan party files
- Defer party-popup relayout so the selection commits
- Move "edit parties" out of the party popup
- Name shards after the real hero + repaint chooser popup title
- Launch the party the user selected (capture rendered selection)
- New party starts empty + header reads "new party"
- Make + add member dropdown exclude by identity, not label
- Show a party member's real hero name, not its label's catalog match
- Constrain YOUR CHARACTER bar to one column width
- Move YOUR CHARACTER to Heroes page + fix roster overlap
- Unclip continue-quest button + always show selected party
- Preserve typed party name + dedup by identity in editor
- Stable hero identity on party members + local parties
2.75.10
- Fixed a crash while a Quest is running. The app could hard-crash (and take the window down) when a quest party was active — the quest panel's color lookup choked on a duplicate member name. It now tolerates duplicates safely.
- Quest messages no longer leak between projects. If you switched to another gem while a quest was still running in the first, that party's chat could get injected into the wrong project's shards. Quest delivery now stays scoped to the gem the quest is actually running in.
2.75.9
- Quest announcements post once, not N times.
quest_announcenow drops a single line in #quest and pokes each hero's terminal once, instead of fanning out a copy per teammate — roughly half the chat noise gone, and broadcasts reliably reach everyone. - The party narrates what it's doing. Claims, task hand-offs, and summaries now show up as compact lines in the #quest chat, so you can follow (and jump into) the coordination without reading every agent's prose.
- Live hero health + roles. Quest heroes now report their real role and context level even with the chat panel closed, so the health view and auto-recovery have live data instead of blanks.
- The party you pick is the party you get. A custom hero you made by duplicating a built-in no longer sneaks into a party by sharing the original's role — party membership stays exactly what you selected.
- Fixed a crash from tooltips. A use-after-free when tooltips were shown could crash the app; tooltip owners are now retained correctly.
- Cleaner hero migration. Stopped a one-time migration from cloning built-in heroes as stray "(custom)" duplicates.
2.75.8
- Refuse to start a quest rooted at the home directory
- Size the editor panel so the save button is on it
- Persist heroMode across show()'s internal dismiss
- Persist --status from quest_heartbeat
2.75.7
- Persist quest-bus membership so chat survives restart
- Keep the editor's save button on-screen
2.75.6
- Show quest-party shard costumes in hover card + profile modal
- Re-resolve party members against live catalog at launch
- Point Sparkle zip enclosure at the download proxy
2.75.5
- Ship Sparkle updates as a zip, not the DMG
- Hover mini card + expand to full profile modal
- Restore hero costume on last-session relaunch
2.75.4
- Blank the chat topic line instead of a bare #quest label
- Allow standalone self-summary without --task-id
2.75.3
- Stop quest heroes inheriting the selected shard's cwd
- Bind staggered summon to target gem by identity
2.75.2
- Show gem icon in quest chat header + fix pill label
- Validate + lowercase hero names at save
- Materialize hero shards when party uses custom heroes
2.75.1
- Kill multi-agent terminal text overlap via per-row content hash
2.75.0
- In-app create/edit for local heroes + LOCAL column polish
- Read charter from hand-authored .crystl/heroes JSON
- Persist hero charter through party.json round-trip
- Author charters for the built-in hero catalog
- Scaffolded Charter field in the hero editor
- Inject hero charter into quest + solo system prompts
- Add QuestRole.charter field
- Align columns, color names, dupe, LOCAL header/subheaders
- Custom heroes selectable + resolvable in quest parties
- One-time migration of flat overrides into custom heroes
- Dedicated Heroes settings page + slim the Quest page
- Stop writing flat override dicts for built-in edits + library import
- Duplicate-&-edit built-ins into named custom heroes
- Fold global custom heroes into catalog + /heroes with precedence
- CustomHeroStore global CRUD + dupe guard
- Add CustomHero record + LocalHero avatarId
- Find bar lands on the topmost match; note count is a hint
- Collapse split to a single Cmd+D toggle; drop dead pane items
- Cmd+F find in scrollback
- Cmd+Opt+1/2/3 facet-slot hotkeys
- Gem/shard/pane navigation + Cmd+K clear
- Add crystl shard close
- Gate the per-chunk dirty kick during mode 2026 sync frames
- Write MCP-trust flag into isolated worktrees so agents don't re-prompt
2.74.0
- Launch the first hero by session identity, not name lookup
- Honor the project's persisted active party for CLI quest start
- Honor --model when summoning a solo hero shard
2.73.1
- Apply global hero customizations to solo summon
2.73.0
- Solo hero shards — summon a catalog specialist on its own
- Keep manual selection alive during streamed output
- Cmd+click to open any file path or URL
2.72.0
- Drop free-tier count caps — unlimited gems, shards, facets
- Monospace the sidebar group headers
- Inclusive, shorter page description
- Swap settings columns — library left, slot buttons right
- "Your prompts" → "Your facets"; subcopy names prompts + commands
2.71.0
- Translucent overlay scroller to match the glass panel
- Anchor to the default sidebar + add a workbench step
- Rename "backlog" to "workbench" (user/agent-facing, back-compatible)
2.70.0
- Add license + connect iphone to the app menu
- Sync push opt-in with the real system permission
- Suppress the push banner for the shard you're viewing
- Apply notification deep link on cold launch / after pairing
- Gate phone pairing behind Guild, show upgrade prompt
- Richer quest party in demo mode (3 heroes, multi-hero thread)
- Make the push opt-in card specific about phone notifications
- Make email the expected default on bug reports
- Tell agents to offer a reply email on bug reports
- Fast-poll the transcript while the agent is working
- Broadcast working/idle on hook edges so phone dots track all agents
- Lowercase the crystl wordmark in the app menu copy
- Suppress "live updates lost" banner in demo mode
- Lock the app to portrait
- Tell agents to interview + investigate before filing a bug report
2.69.0
- Quest button going dead after the setup panel is dismissed
- Stop the ping burst when reopening a quest with history
- In-panel "start fresh?" launch step with a back button
- Keep setup panel open when editing in a child panel
- Relaunch each hero's agent when resuming a quest
2.68.0
- Click-to-reveal description + sane new-item focus flow
2.67.0
- Add fanout worker protocol to PromptTemplates + settings page
- Draggable gem reorder + marquee fix
2.66.0
- Move default spawn agent to top of left column + layout fixes
- Wrap the default-agent description + clearer title/copy
2.65.0
- Hand focus back to the terminal after committing an edit
- Hover states for the + new / + item / + section pills + backlog handle
- Show which conversation you're in + color the DM list
2.64.0
- Keep the sender color when a message is clicked
- Polish the chat sidebar — hover, channel order, DM hint
- Keep the intro logo out of hero DM channels
2.63.0
- Extend the drawer to the full right column
- Scroll the CRYSTL QUEST logo with the message flow
- Rebuild terminal rows after a sidebar-mode toggle resize
- Stop the screenshot bar sliding under the open drawer
- Re-hide gem header when flipping out of Settings in tab-bar mode
2.62.0
- Launch agents on a task via
shard create --agent/--prompt - Bind remote access on the flag alone, not the async license
- Detect tunnel-port conflicts and add
crystl ssh bridge-address - Apply per-hero model at quest start instead of clobbering it
- Add settings toggle for the SSH preflight diagnostic
- Warn in-terminal when remote agent notifications can't reach Crystl
- Inject CLI/backlog snippet when picker reconfigures a gem in place
- Guild upsell on the mobile settings toggles
- Full-gate remote access on Guild license
- Advertise quest, fs, open/close, askuser, facet in the CLI snippet
- Autoscroll long gem titles on hover
2.61.0
- More breathing room above the CHAT HISTORY section
- CHAT HISTORY header + explanation in setup panel
- Roomier clear/start-fresh confirm with header + explanation
- Preserve party roster across archive, don't lose definitions
- Crystl quest start CLI command
- POST /quest/start bridge route to launch a party headlessly
- Crystl quest clear CLI + POST /quest/clear bridge route
- Continue/start-fresh launch prompt + manual clear button
- Archive-not-delete primitive for clearing chat history
2.60.0
- Claude's chat speaker tag in its brand orange
- Chat tracks the agent's reply live, not on a 18s lag
- Quest logo caption text style, fanfare off-main, accurate comment
- /quest returns no messages when the quest is inactive
- Push quest end on shard/gem close, not just explicit endQuest
- Refresh gems only on quest membership change, not per message
- Match desktop quest hero colors (was 3 purples)
- Refresh the phone when a quest ends (stale conversation)
- Tile the quest logo pixels + typewriter font on awaits screen
- CRYSTL QUEST logo on the quest tab's "awaits" screen (was swords)
- Phone registers a desktop-launched quest immediately (was ~8s)
- Quest logo as a fit-to-width default screen, not a clipped flash
- CRYSTL QUEST intro overlay on quest-chat open
- Port the synthesized quest fanfare to iOS
- Restore the launch intro (logo + fanfare) — join was posted too early
- Persistent per-hero colors in the quest chat (match desktop)
- Resolve Claude transcript by the file it's writing, not argv/mapping
- Submit injected quest paste with a separate, delayed double-Enter
- Delta-aware screen refresh in the shard VM (Phase 3)
- Row-delta screen responses via ?base= (Phase 3)
- Screen row-delta DTO + pure apply (Phase 3)
- Push-driven shard refresh, drop the fast 1.5s screen poll
- Emit unified, sequenced shard_update (screen + transcript)
- Shard_update event DTO, gap helper, and stream/VM wiring
- Resolve Claude transcript from argv, in front of the mapping
- Expose a shard agent's process argv (AgentMonitor.agentArgs)
- Terminal tab polls fast again (was lagging ~18s after the SSE work)
- Don't serve the previous Claude session right after a summon
- Brighten + "agent" badge on backlog tasks an agent touched
- "+ item" opens the editor — add title + description in one step
- Backlog section header rename + delete via context menu
- Backlog section rename + delete plumbing
- Backlog section rename + delete routes
- Delete a section header on desktop (tasks survive)
- "+ section" no longer discards its draft instantly (desktop)
- /send writes Enter twice so a busy TUI doesn't drop it
- Mobile sticky "+ item / + section" add bar
- Desktop sticky "+ item / + section" add bar
- Bridge POST /backlog/section route
- CrystlKit empty-section path (addBacklogSection)
- Inline "+ section" affordance + click-to-rename headers
- BacklogStore.renameSection(at:to:)
- "+ section" button on the drawer instead of typing ##
- Create sections from the desktop drawer (## syntax)
- Tap a backlog task to edit its title + description
- Backlog tab to parity — multi-line detail, 3-state cycle, section picker
- Keyboard no longer covers the backlog add-task field
- Fall back to newest session when Claude's mapped one is a phantom
- Pull-to-refresh re-dials the connection, not just re-fetches
- Backlog as a 3rd tab — content API + live editable list
- Pin hookless agent sessions per shard so shared-cwd shards don't collide
- Up-front Guild affordance — disable mutating controls when !canMutate
- Push agent_status_changed over SSE; fold status into screen/transcript
2.59.0
- Group sidebar nav under section headers
- Agent-change badge + longer flash
- Settings on/off + auto-open on new items
- Crystl backlog open/close/toggle
- Flash on detail edits, indent grip, align open count
- [~] in-progress task state + change-flash
- Retry transient relay failures with backoff
- Clarify crystl docs id-vs-search header comment
- Match window background, side/down carrots, drag-to-reorder
- Crystl-aware agents — crystl docs + crystl report
- Crystl facet — manage facet inserts + bar slots
2.58.0
- Create CLAUDE.md + AGENTS.md when a project has no agent doc
- Tell agents about the backlog + history; broaden agent coverage
- Editable per-gem backlog in a right-edge slide-out drawer
- Run command inserts via Claude bash mode (! prefix)
- Tag inserts as cmd or prmt, show pill in bar dropdown
- Re-dial the tunnel on system wake and network changes
- Add heartbeat ping/pong to detect dead tunnels
- Don't let a transient hello_err kill the tunnel forever
2.57.0
- Lead the heroes column with a Hero System / hero stats key entry
- Honor local heroes' explicit
heroname with collision handling - Local-heroes picker + guardrail tagging in setup panel (Phase 2)
- Project-local guardrail heroes from .crystl/heroes/
- Per-gem auto-approve picker writes the dir the bridge reads
2.56.0
- White labels for Codex plugin/skill rows (were black)
- Gap between troubleshooting blurb and the copy button
- Tighten captions under the field + button on Remote page
- Drop redundant toggle blurb; 'your Mac's bridge'
- Restructure Remote page — neutral lead, troubleshooting section, help icon placement
- Lead the Remote page with its use case
- Clearer remote-install button + copied flash
- Dedicated Remote page; move SSH out of Claude
- Resume uses the hero's configured agent, not hardcoded claude
- Keep quest verbs on PATH when an agent session resumes
- Clearer dropdown affordance on facet pills
2.55.0
- Isolated shards are now hard-blocked from editing files outside their own worktree — an agent in an isolated shard can no longer accidentally modify the main checkout
- More reliable hooks: approval prompts and side-quest messages now authenticate correctly over the local unix socket (no more silent 403s)
2.54.0
- Include bridge port on the unix-socket message path
- Send bearer token on the unix-socket hook path
- Hero editor model is free-text for every agent, not a Claude-only dropdown
- Quest open panel shows each hero's agent + an edit pencil; drop 'Requires Claude Code'
- Codex turn metrics — parse rollout JSONL for the turns panel
- Turns panel recognizes Fable (1M) and stops mislabeling unknown models as Sonnet
2.53.0
- Never symlink tracked config files into worktrees
- One agent-badge convention across all agents in panel headlines
- Badge non-Claude agents in panel headlines next to the shard name
- Summon keeps hero-editor agent choice over party-blob default
- Agent-aware resume gate + quest fallbacks
- Quest launch path resolves the hero's agent via AgentLaunchSpec
- Agent picker in quest hero editor
- Per-hero agent field on QuestRole + questAgents persistence
- AgentLaunchSpec — per-agent quest launch table keyed by AgentKind
- Codex hook adapter — approval panels + notifications via codex hooks
- Thread agent identity through bridge + panel headlines
- Add optional agent identity field to PendingRequest + HookNotification
- Antigravity CLI transcript backend — SQLite + protobuf walk
- Detect Google Antigravity CLI (agy)
- Codex/gemini session view + waiting-prompt detection
- Session view is the default for every shard
- Task cancellation is benign, not 'Network error: cancelled'
- Line-drawn Lucide tab icons for approvals + questions
- Welcome screen fits whole — auto content-width fit in session embed
- Flip the session-store split — Crystl takes the new filename
- Identity-split Stone vs Crystl session mappings
- Splash glow stays on the track, ping-pongs instead of snapping
- Splash progress glow in brand icy blue (accent), not peach
- SessionStart hook remaps shard→session immediately
- Session view lands at the bottom, capped to the last 200 rows
- Persistent CI signing identity via repo secrets
- Archive with the cloud Distribution cert, not per-run dev certs
- Session view shows live terminal until the conversation starts
- Agent-working pulse on gems page
- Auto-trust pre-existing project MCP servers on gem open
- Detect agent stalled on hook-less TUI prompts, notify + push
- Splash progress — slow blush glow instead of orange dot
- Reset relay route memory on foreground
- Pair-device relay toggle + AppDelegate RelayClient wiring
- RelayClient — WS tunnel, loopback replay, reconnect
- MacId + macSecret identity provisioning
- Swift frame codec for the relay wire contract
- Persist relay endpoint with the pairing
- LAN→relay per-request fallback with session route memory
- Pairing payload v2 — relay + mac_id
- Route-aware endpoint requests
- Tap-to-talk mic button in the send bar
- Branded launch splash — glowing crystal, serif wordmark, progress line
- Terminal pinch-zoom + fit double-tap; agent-less shards open on terminal
2.52.0
- Report-bug link in the Help menu
- Match the open-button shine to the quest button
- Loop the open-button shine until the user moves on
- Shimmer the open button to cue a selected folder
2.51.2
- Treat checksum-less party.json as managed, not frozen
2.51.1
- Restore DMs channel list opacity so it renders when shown
2.51.0
- Fade gem rows at scroll edges instead of a shadow overlay
- Keep AskUserQuestion panels until answered
- Glow halo on the unconfigured folder icon
- Recursive folder search, path typing, and open button
2.50.0
- Recolor letter-icon preview when the color changes
- Make the PROJECT DIRECTORY field typeable
- Stop gated-quest warning from overlapping the requires note
- Quest panel reads party roster from resolver
- Warn when a hand-edited party.json is undecodable
- Never regenerate a hand-edited party.json
- Resolve party roster from user-owned party.json
- Decode v2 party.json into QuestParty
- Managed party.json writer + ownership checksum
- Load saved hero stats on editor reopen
- Strip OSC 7 file:// URI from session cwd
2.49.0
- API transcript handler uses per-agent TranscriptSource
- Drive the navigator panel through TranscriptSource
- RemoteFileAccess SSH backend for transcript sources
- Gemini session resolution (registry + legacy hash)
- Gemini chat parser (user/gemini → events)
- Recognize Google Gemini CLI as an AgentKind
- Codex session resolution by session_meta cwd
- Codex rollout parser (response_item → events)
- TranscriptSource protocol + factory + ClaudeTranscriptSource
- Add TranscriptFileAccess protocol + LocalFileAccess
- Auto-publish appcast to crystl-web + deploy
2.48.0
- Default to sidebar mode + redesigned two-row header
- Empty/remote rail states, remove dead picker/scrollback code
- Search field + results across the gem's sessions
- Auto-open the active shard's session
- Highlight the rail moment matching scroll position
- Moment↔scroll index and jump-to-moment in the right pane
- Rail moments state with back navigation
- Rail session-list state (replaces scrollback list)
- Clamp the panel on-screen so the larger 660x520 panel stays visible
- Add background gem-wide search driver
- Add per-session unified search (conversation + tools)
- Add moment extraction for the navigator rail
- Hide picker rule on Scrollback, picker tooltips, row hover
- Taller panel, top-align scrollback, clickable rows
- Stop main-thread freeze when opening the history panel
- Validate transcript sessionId to block path traversal
- Empty-states (remote/Codex), picker visibility, polish
- Add Conversation + Tools transcript tabs with session picker
- Convert HistoryPanel to tabbed shell with Scrollback tab + clear control
- Append session-log record on each save
- Add append-only claude-session-log for shard tagging
- Add SessionHistory.clearOlderThan(days:)
- Add SessionHistory.clearAll for scrollback cleanup
- Add crystl history CLI command
- Fetch remote transcripts over SSH for the transcript route
- Serve GET /gems/:id/shards/:sid/transcript (local)
- Add TranscriptRow/TranscriptResponse wire types
- Load + list transcripts from a bucket dir
- Parse flat JSONL transcript with tool pairing
- Derive per-tool summary one-liners
- Add transcript bucket-path encoding
- Add TranscriptEvent model for Claude transcript parsing
2.47.2
- Log the two silent /hook drop points (401 + external-session filter)
2.47.1
- Log when a notification is dropped by the per-type enabled gate
2.47.0
- Tolerate create-dmg AppleScript styling failure
- Target the bridge that spawned the shard, not the newest token file
- Make crystl approve/deny report whether a request resolved
- Detect uncommitted worktree work instead of silent nothingToMerge
- Make smart auto-approve in-scope work (F3)
2.46.1
- Stop bar at sidebar divider + fade overflow edges
2.46.0
- Insist workers report DONE/BLOCKED as a required final action
- Gate control commands behind Guild (read-free, control-gated)
- Suppress approval/notification panels for orchestrator-managed workers
- Decode crystl pending without snake_case conversion
- Pre-trust the canonical (symlink-resolved) worktree path
- /fanout orchestration command + auto-provisioning on launch
- Pre-trust worker worktree so it runs unattended
- Reject malformed quest_msg without polluting the channel
- Clarify context-window step copy
- Add project optimizer step opening the ⋮ menu
- Retarget gem settings step at the ⋮ menu
- Pin CRYSTL_QUEST_ROOT so --approval+--quest workers write to gem root
- Reject remote isolated shards instead of mis-merging locally
- --quest installs fanout comms channel at shard spawn
- Crystl merge command for isolated shards
- --approval at shard spawn
- Scope log dir by AppIdentity.name so Stone stops writing into Crystl's
2.45.0
- Add optimize item to gem ⋮ menu
- Optimizer header shows large gem name + icon
2.44.0
- Mirror gem ⋮ menu + hover close on sidebar gem rows
- Gem-tab ⋮ menu (history/settings/approval); remove GemToolbar pill
- add TabControlGeometry helper for gem-tab hover controls
2.43.0
- Address pre-ship review (resize-safe disable, hover band-gate, observer cleanup)
- Settings icon uses a native tooltip instead of a clipped hover label
- Move settings icon inward so its hover label isn't clipped
- refine sidebar: align SHARDS with shard text, label footer + new gem
- Don't reveal the tab bar over the sidebar after leaving settings
- refine settings: more space below APPEARANCE/BEHAVIOR headers
- refine settings: more header space, independent columns, squarer diagrams
- Two-column general settings + sidebar-mode illustration
- Larger gem sidebar rows (14pt names, 18px icons)
- refine sidebar: align SHARDS with GEMS, wider bar, larger gems, more gutter
- Stacked two-row shards bar in sidebar mode
- Optional stacked two-row layout for SessionBarView
- refine sidebar layout: terminal gutter + shards bar aligned with gems header
- refine gem sidebar: drop redundant open-folder button, improve spacing
- Add sidebar-mode settings toggle
- Sync gem sidebar from updateTabBar
- Wire gem sidebar into window layout with window growth
- GemSidebarView vertical scrollable gem list
- GemRowView for sidebar gem list
- Sidebar-mode window geometry helper
2.42.6
- Submit injected paste under kitty mode without report-all-keys
2.42.5
- The context button shows the live turns-left count again. The recent rework had reduced it to a plain "turns" label; the "~N turns left" estimate is back on the button (auto-sized so large counts don't clip) and updates each turn.
2.42.4
- Drag-to-select now auto-scrolls. Pull the cursor to the top or bottom edge while selecting and the terminal scrolls so you can select more than a screenful. Holding at the edge keeps scrolling, releasing stops it.
- Fixed scrollback getting stuck in some sessions. When an app enabled mouse reporting it was eating the scroll wheel even in the normal buffer, so you couldn't scroll back through output. The wheel is now only handed to full-screen apps (tmux/vim); otherwise it scrolls your history.
- "Agent finished" notifications show by default. Subagent completions are now treated the same as the main agent finishing, instead of being off until you opted in.
- Fixed notifications overlapping the Crystal Rail. After dragging the rail from a side to the top, floating notifications now re-align below it without needing to be dismissed first.
2.42.3
- Notifications now come through for Claude running over SSH. Idle prompts and questions from a remote session were being silently dropped, and only locally-run agents surfaced panels. Remote sessions now raise the same idle, question, and subagent notifications as local ones, while non-crystl agents in other local terminals stay filtered out.
2.42.2
- Auto-approve now follows the project you're working in. When a shard worked inside a project nested under a broader gem (e.g. a home-folder gem), the gem's approval mode could shadow the project's, so a project set to "all" still prompted for every tool. Approval mode is now resolved from the working directory first, and the rail's approval picker reflects the mode that's actually in effect.
2.42.1
- Formations keep your gem names again. Renaming a gem in Gem Settings now sticks when you save it into a formation. Previously the gem came back with its folder name instead of the name you gave it. (Formations saved before this fix need one re-save to pick the names back up.)
2.42.0
- Context "turns left" estimate fixed for large-window models. It now reads the real context window for newer models (e.g. Opus 4.8's 1M window) instead of assuming 200K, so the countdown is realistic instead of hitting 0 about five times too early.
- The context button is always available. It appears as soon as an agent is running (labeled "turns" with a subtle button border) and opens even before the first turn lands so you can still see the fixed-cost breakdown.
- Redesigned the context panel header. A larger "token usage · gem · shard" title with the gem's icon inline, and the model and window size on the line below.
- The per-turn cost list scrolls. Setups with lots of plugins and skills no longer push the panel off-screen; the column headers and total stay pinned.
- Plugin and skill rows are clearly clickable. They highlight on hover and pop their menu on a click anywhere along the row.
2.41.0
- Subagents are identified in panels. Each gets a stable dwarf name, a pickaxe glyph, and a "sub · <role>" line on both approval cards and notifications, so parallel subagent activity is easy to tell apart.
- Notifications stack. A deck-style peek instead of being dropped once more than four arrive.
- Redesigned the Gem Settings / New Gem panel into Identity and Agents tabs, never runs off-screen, with a ROOT FILES drawer and consistent spacing.
- Codex plugins & skills moved to the Codex settings page (they're global, not per-gem); the gem panel now links there.
- New-gem "initialize git" and remote URL moved to the Identity tab.
- Fixed Crystal Rail badge clipping.
2.40.0
- Master ENABLE toggles in Gem Settings. The plugin, skill, and MCP sections each get a top-level enable toggle.
- Fixed a stray "Butt" label leaking onto icon-only buttons (the NSButton default title).
- Update-check ping includes license plan (free / pro) so anonymous free devices are labeled.
2.39.0
- Plugin recommendation catalog grew from 5 to 23. The optimizer now recognizes 18 more Claude Code plugins when their detection signal fires, covering databases / backends (Firebase, MongoDB, Neon, PlanetScale, Convex, Appwrite), auth (Auth0, WorkOS), frontend / framework (Expo, Apollo GraphQL, Sanity, Shopify, Mintlify), email / messaging (Resend, Twilio), observability (PostHog, Datadog), and Netlify for deploys. Detection is the same shape as before: manifest file (
firebase.json,netlify.toml,convex.json, etc.) or apackage.jsondep prefix (@neondatabase/,mongoose,@auth0/, etc.). When a match fires and the plugin isn't installed, the optimizer's setup section shows+ install <plugin>; one click types/plugin install <id>into the gem's selected shard.
2.38.0
- Optimizer recommends Claude Code plugins. Open the optimizer in a Vercel / Supabase / Cloudflare / Sentry / Stripe project (detected via
vercel.json,wrangler.toml,@vercel/*/@supabase/*/@sentry/*/stripedeps, etc.) and the setup section shows a one-click+ install <plugin>row. Clicking it types/plugin install <id>into the gem's selected shard, then watches~/.claude/plugins/installed_plugins.jsonfor 30s and auto-rescans so the gap disappears once install completes. If the plugin is already installed but disabled for that gem (via the context-load panel right-click), you get+ re-enable <plugin>instead, one click strips the disable entry from.claude/settings.json. The catalog ships asResources/plugin-recommendations.jsonso adding new plugins is a JSON commit, no Swift edit. - Astro project detection. Projects with an
astro.config.mjs(or.ts/.js) now get an "Astro project" profile in the optimizer instead of falling back to generic Node.js with linter / logging nudges. - Optimizer setup checks are scoped clearly. The setup-tab rows now read "No X in this directory" so it's obvious the optimizer grades the gem's onboarding, not your global Claude config. The misnamed "Claude skills" check (which was actually testing
.claude/commands/) is now correctly labeled "slash commands," and a real.claude/skills/check was added alongside it. - Gem Settings: Claude/Codex label parity. Claude accordion sections now read "INCLUDE CLAUDE SKILLS?" / "INCLUDE CLAUDE PLUGINS?" matching the Codex labels, less ambiguous in mixed-agent gems.
- Context-load panel refreshes in place. Disabling or re-enabling a plugin/skill from the turns panel now updates the strikethrough row and totals immediately. Previously you had to close and reopen the panel to see the change.
2.37.0
- crystl CLI. A
crystlcommand-line tool ships inside the app bundle. Install via Help → install command line tool… (one admin prompt, symlinks/usr/local/bin/crystl) or from Settings → General → Command Line Tool. From any terminal:crystl gems,crystl shards --gem <name>,crystl screen,crystl send,crystl pending,crystl approve/deny. Full reference at crystl.dev/docs/cli. - New CLI commands.
crystl shard create --gem <name> [--isolated] [-c "<cmd>"]spawns a sibling shard so orchestrator agents can fan out parallel work.crystl eventsstreams the bridge's SSE event log as JSON lines, pipe-friendly with jq.crystl wait pendingblocks until a permission request appears, built on SSE, no polling. - Agents discover the CLI automatically. Each gem's
CLAUDE.mdandAGENTS.mdget a short marker-bracketedCrystl CLIsection upserted on open, so any agent inside a crystl shard knows it can coordinate with sibling shards. Idempotent (re-runs upsert in place), only touches files that already exist, gated by a General settings toggle. - CLI fixes from first round of testing.
crystl opennow reportsPath does not exist/Path is not a directoryinstead of a generic failure.crystl closeaccepts gem name (was UUID-only despite the help text).crystl screentrims trailing NULs sogrepstops silently exiting 1 on the output.crystl sendappends\rby default so commands submit in shells and TUIs (Claude Code, vim); use--no-enterto opt out.
2.36.37
- Stale panels auto-dismiss. Ask-user, approval, and notification cards now disappear when the agent moves on, rather than sitting orphaned until you click. New rules cover
SessionEnd(drops everything pending for that session),PostToolUsematching an open approval (the tool already ran), a shard restarting its agent (different Claudesession_idfor the same shard UUID), and the big one, any follow-up hook for a session with an open question proves the agent moved past it without your panel's answer. The 5-minute hard timeout stays as a backstop. - Notification cards finally auto-dismiss. The dismiss timer slot existed but was never populated, so informational cards stacked indefinitely. Now they fade after 8 seconds by default, question cards still persist until you click Answer or Dismiss. Tunable via the
notificationAutoDismissSecondsUserDefault (set to 0 to disable). - CrystalRail polish. The tile strip now scrolls when it exceeds 80% of the screen instead of overflowing off the edge. Fixed the top of the rail disappearing after closing a gem from the middle of the strip.
2.36.36
- General settings polish. The
allow notifications from other terminalstoggle now carries a caption explaining what it does ("allows crystl rail to display agent notifications from other terminals"), and the toggle label gains a leading verb so the action is unambiguous. Fixes layout overlap in Settings → General: theSESSION RESTOREsection header no longer collides with therestore last session on startuptoggle pill, and the GPU rendering / external-notifications subcopy hints no longer crowd the toggle below them.
2.36.35
- Notification isolation for other terminals. Claude invocations running outside crystl (Terminal.app, iTerm, Warp, Ghostty, tmux, a cron job, anything) no longer surface in crystl's rail by default. New
notifications from other terminalstoggle in Settings → General flips the behavior back on per machine. SSH-tunneled and Tailscale/LAN sessions are unaffected and keep working regardless of the toggle, since remote Claude can't supply crystl's session env vars. Also fixes a clobbering bug when two builds were installed side by side: the shared~/.claude/crystl-hook.shwould route hooks to whichever installed last; each build's spawned shells now stamp the bridge port, socket, and token-file path into env so the script reaches the right bridge.
2.36.34
- Tab and context-bar polish. Long gem-tab titles no longer crash into the close
×: the glyph is 10% smaller and sits 8px from the tab's right edge (was 12), with a real 6px gap before the text clip. The~N turns leftindicator in the status bar now brightens fromalpha 0.5to1.0on hover so its clickability is obvious instead of reading as a static label. The welcome tour adds a 13th step explaining the context-window indicator and what it points to. The real button only appears after three turns, so the tour materialises a mock at the same position during the step.
2.36.33
- See and shrink the plugin / skill context load per gem. The
~N turns leftpanel now itemizes every installed Claude Code plugin and user-level skill alongside CLAUDE.md / AGENTS.md / .mcp.json. Each row shows lines, tokens, and % of window. Left-click any plugin or skill row to disable it for the active gem, for all gems, or (for Codex) globally; disabled rows render grayed with a strikethrough and a one-click re-enable action. Claude disables write.claude/settings.jsonand inject/reload-pluginsinto the active shard so changes apply mid-session; Codex disables write~/.codex/config.tomlwith a "restart codex to apply" note since Codex has no per-project scope. Plugin and skill checkboxes also appear in the New Gem and Gem Settings panel as collapsibleINCLUDE PLUGINS?/INCLUDE SKILLS?sections, plusINCLUDE CODEX PLUGINS? (global, restart codex)for Codex. New gems with a recognized stack (Vercel, Shopify, Cloudflare, Supabase, Sentry, Swift) get an opt-in dialog proposing which plugins to enable / disable. Bug fix: the turns-remaining button now appears reliably after three turns even when agent detection is mid-cycle.
2.36.32
- Welcome tour: 12 steps, follows the window, replays from Help. The first-run tour now covers isolated shards, quest / side quest, the screenshots bar (it opens automatically during its step), and ends on a centered farewell with a one-click join slack CTA. Bubbles attach as child windows so they track parent moves through drag, fullscreen, and screen-to-screen jumps. Chevrons now land on the actual control they describe (the
+, the isolation dropdown, the quest button, the facet pills) instead of the wide bar’s midpoint. Crystal rail step mentions drag-to-dock on the left, right, or top edge. App settings step calls out the trio that actually matters: API keys, MCP servers, and CLAUDE.md / AGENTS.md editing. New Help → show welcome tour menu item replays it on demand.
2.36.31
- Notifications: timestamps on the headline. Notification cards now show when they were created,
diamond notification - just nowfor fresh cards, switching to absolute time (diamond notification - 7:35pm) at the 60-second mark via a one-shot per-panel timer. Lets you tell at a glance whether a long-lived notification is current or stale instead of having to dismiss-and-wait-for-the-next-one. - Shards: stop nagging on every shared shard in home-rooted gems. The home-directory warning was firing on every shared-shard creation, not just isolated attempts, far too noisy for users who intentionally have a home gem. Isolated shards in home still refuse loudly (they’d scatter worktrees under
~/.crystl/), but shared shards now create silently.
2.36.30
- Invisible-text-on-glass: defensive widening on PTY data. The known “text gone, drag-select makes it appear and stay” signature recurred. Classic renderer-side bug where SwiftTerm’s per-row dirty marking missed a buffer update under heavy Claude Code output, so the renderer’s row cache kept serving stale bytes. Selection works because
selectionChangedwidensmetalDirtyRangeto the full visible range. Mirrored that widening into the existingdataReceivedkick via a newcrystlMarkVisibleDirty()patched onto SwiftTerm. Every PTY chunk now guarantees the next Metal draw rebuilds visible rows from current buffer bytes. Belt-and-suspenders on top of themetalDirtyRangeunion patch: that one fixes writer-vs-writer clobbering; this one defends against writers that miss rows entirely.
2.36.29
- Syntax-highlighted type tokens readable on glass. Claude Code’s Monokai Extended theme emits lone
\e[2m...\e[22mfor both ghost-text hints AND code-block type tokens (UInt8, ArraySlice, etc). The SGR rewriter was injecting gray-120 as the lone-dim substitute, visible enough for input-bar placeholders, but invisible-dark on glass for code-block types that use the same bytes. Bumped to gray-180 so both render visible-but-distinctly-dim relative to typed input (which lifts to white). - Renderer fg luminance floor catches tinted greys. The SwiftTerm-side floor only lifted pure greys (channel diff < 30) to white, lightly-tinted muted syntax-theme colors at diff 40 to 70 slipped past and rendered invisibly. Widened to diff < 80; saturated theme accents (diff > 100) still pass through unchanged.
- Tab bar: clear gap between × close and + add buttons. With
tabSpacing=2, the “+” was rendering essentially flush against the trailing tab’s “×”. Bumped the “+” offset so there’s a 10px clear gap. - Session bar: inset quest/isolation buttons 28px from right edge. The right-edge inset was 14px, crowding the close-window chrome. Centralised the margin in a constant and bumped to 28.
- Crystal Rail: settings diamond back inside the glass capsule. The May 6 wrapper restructure (which correctly stopped alpha cascading from dimming tile icons) inadvertently floated the settings diamond above the rail with a visible gap. Returned just the settings icon to glass, tiles still sit outside glass so their alpha doesn’t cascade.
2.36.28
- Alpha floor: three small text/icon sites lifted from 0.4 → 0.5. crystl’s text alpha floor is “no text in the app should be less than white alpha 0.5”. Three sites still violated it: the QuestPanel subtitle (the · separator and gem name), the DirectoryPicker file icon color, and the TemplateLibraryPanel label badge. Visual polish only, minor brightening of subtle UI affordances against the dark glass background.
2.36.27
- Quest prompt restructured: comms rule first, explicit negative, concrete example. Real-quest feedback from a ranger shard that replied to the user with plain text instead of going through
quest_msg. Asked the shard what would have made the rule stick, then applied its three suggestions verbatim: (1) moved the comms rule to the top (was buried mid-block after recon instructions); (2) added an explicit negative (was “use quest_msg”, now “NEVER respond to the user with plain text” with the consequence (“plain-text replies are invisible to the user”); (3) added a 4-step concrete example of what a first response should look like, because examples beat descriptions when there are 20 competing rules. Also broke the wall-of-text into section headers so the model can scan structure rather than parsing one long paragraph.
2.36.26
- “No conversation found” on startup, actually fixed this time. The v2.36.24 check rejected resumes when Claude Code had deleted the conversation file entirely, but missed the case where the file exists in a *different* cwd’s project bucket. That’s what was happening on most affected sessions: a shard was originally
cd’d into one directory when its Claude session was saved (say~/Nextcloud/promptreviews), then the gem’s resolved cwd changed (back to~). The conversation file lives in the original cwd’s bucket butclaude --resume <id>from the new cwd only looks in the new cwd’s bucket. crystl now encodes the path the same way Claude Code does (each/→-) and checks the one specific bucket the autorun script will actually run from. Mismatch → no autorun written → clean prompt.
2.36.25
- Quest messages now actually reach the agents when multiple gems share a path prefix.
bestProject(for:)had a longest-wins tiebreak that picked the wrong gem when two gems both overlapped the query cwd, specifically when one gem was AT the cwd and another was nested deeper. Quest delivery then iterated the deeper gem’s sessions, found no quest shards (the quest was in the shallower gem), and silently skipped the message. Symptom: chat panel UI showed your typed message, but agents never received it. Fix: prefer exact match first, then deepest-cwd-contained, then SHALLOWEST-gem-inside-cwd so a gem AT the cwd wins. Also tightens prefix comparisons to require the path separator so/Users/chrisdoesn’t spuriously match/Users/chrissomething.
2.36.24
- No more “No conversation found with session ID” error on startup. When crystl restores a shard via session resurrection, it writes
.crystl/autorun-<shard>.shcontainingclaude --resume <id>, which the shell sources at prompt start. If Claude Code has deleted the conversation file in the meantime (rotation, cleanup, sync drift), the resume command printed a red error to the terminal on every startup until the user did something. Now crystl checks that the conversation file actually exists at~/.claude/projects/*/<id>.jsonlbefore writing the autorun, no file means no autorun, which means a clean prompt. The saved session ID is left in.crystl/claude-sessions.jsonso a later restoration (backup, sync) will resume cleanly on the next startup.
2.36.23
- Fresh “begin quest” summon now actually opens the chat panel. Same class of bug as the v2.36.19 resume fix, and previously masked the same way. The fresh-summon path had a timing race:
injectQuestWrapper(which sethasQuestContext = true) was scheduled for +0.8s after shard creation, but the chat-panel open ran at +0.2s. The chat-open path checkshasQuestContextto decide whether to construct the panel and silently no-opped because the wrapper hadn’t fired yet. Fix: sethasQuestContextsynchronously when the shard is created. The flag represents intent (“this is a quest shard”), not “the wrapper scripts are installed.” Reproducible on a 1-hero party; party size didn’t affect the race. - QuestReportGenerator: empty-string check instead of nil-coalesce. Compile-time warning cleanup,
session.detectedModelIdis non-optional so?? “unknown”was dead code. Switched to.isEmptywhich correctly expresses the “fall back when no model detected” intent.
2.36.22
- Shard label readability: luminance floor + dropped onyx. Some shard pills had crystal colors dark enough to be hard to read on the glass background: lapis, ruby, garnet, cobalt, and tanzanite were the worst offenders. New
NSColor.shardReadable()helper applies a perceived-luminance floor (BT.709 Y ≥ 0.55) at the draw site, multiplicatively scaling channels to preserve hue while lifting darks. Onyx removed from the crystal rotation: it was grey-dark by design and just converged to a generic medium grey after the floor. New auto-allocate order: diamond → opal → jade → lapis → topaz → pearl → amber → quartz → ruby → garnet → emerald → cobalt → peridot → zircon → amethyst → tanzanite → carnelian → turquoise → morganite (19 names). Existingcrystl/onyxworktree branches on disk still appear in the Isolation dropdown as orphans and can be reopened.
2.36.21
- PTY hot-path: cached UserDefaults reads + MTKView subview reference.
dataReceivedfires per chunk of bytes from the agent, 50 to 200×/sec under Claude output. The two diagnostic kill switches (crystlDisableSGRRewriter,crystlDebugBytes) now read once at first reference instead of per chunk, and the MTKView subview is resolved lazily once and cached instead of walked + class-name-substring-matched per chunk. Both flags now require an app restart to take effect. - Pulse animations: shared 20Hz clock, cached questEnabled, alpha-at-draw. Three independent per-view
Timer.scheduledTimers consolidated into one sharedAgentPulseClock, previously 11+ independent timers under a multi-gem multi-shard quest. Bonus: all pulsing surfaces now lock-step instead of drifting in/out. CachedquestEnabledinSessionBarView. Fixed a silent bug where the pulse alpha on shard-bar icons was being dropped before reaching the screen (visible behavior change: thegit-branchandswordsicons now actually pulse / hover-brighten). - UI hot path: async git scans, memoized window title, async file gather. The local
GitWorktree.orphanedBranchescall inrefreshOrphanedWorktreesmoved off main (panel-open path kept synchronous so the badge count is correct on first frame).ChamberSetupPanel’s orphan scan cached so typing in the path field doesn’t re-rungit for-each-refper keystroke.uploadV2StateToRemoteHosts’s file-gather phase moved into the async block.updateWindowTitle()memoized to early-bail on no-op title rebuilds. - Lifecycle cleanups.
DirectoryPicker’s NotificationCenter observer now removed before re-assignment and in deinit. Previously a re-shown picker leaked the prior observer which then fired on every settings keypress (visible as settings UI sluggishness).AppDelegate’s Enter-key NSEvent monitor token now stored + removed at app termination. ThreeAppDelegate+Formationsusleeppolling loops replaced with chainedDispatchQueue.asyncAfter, which no longer pins worker threads at startup with big formations.
2.36.20
- Subprocess deadlock when git or ssh output exceeds 64 KB.
GitWorktree.run,RemoteSession.run, andQuestReportGenerator.collectFilesChangedall calledreadDataToEndOfFile()AFTERwaitUntilExit(). macOS pipe buffers cap at ~64 KB, once a subprocess emitted more than that, the child blocked writing to the pipe while the parent blocked waiting for the child to exit. Classic deadlock; crystl would hang and the parent’s file descriptors leaked until force-quit. Triggered bygit diff --stat HEADon a big-changelist repo,git logon long history, ssh command output past 64 KB. Fixed all three sites with concurrent pipe drains viaDispatchGroupbeforewaitUntilExit. - Title hook: dropped the process-tree scan and heavy state writes. Companion fix to v2.36.18’s orphan-scan-off-title work. Every OSC title update from the agent was still triggering
agentMonitor?.scanNow()(a fullsysctl(KERN_PROC_ALL)walk) andupdateAgentUI()’s file I/O (status.json, per-shard quest writers, healer alert scan, remote SSH upload). None of that data changes because of a title string, it changes on bridge hooks. SplitupdateAgentUIinto a cheap UI-sync version and a newrefreshAgentState()for the heavy work; bridge hook handlers now call the heavy version explicitly while the title hot path stays cheap.
2.36.19
- Quest “resume” button now actually opens the chat and delivers messages to agents. After a crystl restart, clicking the green resume (N shards) button in the quest setup panel would re-attach the worktrees but the chat panel never appeared. Once the chat was opened by other means and a message was typed, the message appeared in the panel UI but never reached the agent terminals. Root cause:
resummonShardscalledopenExistingWorktree(which creates plain isolated shards) but never installed the quest wrapper, so the resumed shards lackedhasQuestContext, which the chat-open path and the message-delivery path both gate on. Wrapper installation now runs on resume at the same cadence as on initial party summon.
2.36.18
- Typing lag during Claude activity fixed. The terminal-title hook was spawning 3 to 5
gitsubprocesses on every OSC title update from the agent. Claude Code emits title updates many times per second while “thinking”, so the main thread was starved of keyboard input the entire time the git scan ran.setTerminalTitleclosure dropped from 43.5% to 3.1% of main-thread time after the fix; the cascade also cutCA::Transaction::commitfrom 61.9% to 45.6% and view backing-layer display from 49.7% to 27.6% (fewer spurious git scans = fewer cascading UI invalidations). Orphan-branch scan now happens only on events that can actually change the orphan set: gem switch, shard create/close/merge, and right before the isolation dropdown opens. - Welcome banner now dismisses on your next command. First-launch banner wipes itself when you run anything in the shell, no more lingering banner under your prompt. Hooks into the shell’s preexec via OSC 7770.
- Fixed a regression where holding the delete key could leave stale glyphs on screen. The forced-repaint kick on PTY data had been removed in a recent change based on an A/B that showed “no regression”, but the test was conducted while another bug was incidentally refreshing the terminal layer as a side effect. Once that bug was fixed (above), the latent invisible-text regression surfaced. Kick restored.
2.36.17
- Cwd-drift warnings when a shard wanders outside its gem. A user who
cd’s from inside gem A into project B’s directory sees their shell happily working in B, but crystl-level features (isolated shards, quest, project settings, MCP) stay anchored to gem A’s directory. Silently. Same class of foot-gun as the home-rooted-gem issue earlier this week. Two complementary nudges: a one-time terminal hint fires when drift is first detected (yellow ⚠ banner explaining the situation and recommending “+” to make a new gem for the wandered-into folder, gated so it fires at most once per user), and a persistent status-bar indicator shows a yellow ⚠ + yellow-tinted cwd text on the project label whenever the active shard is outside the gem’s project tree (reverts to plain text the moment the shard cd’s back inside). Remote shards skip both checks; the auto-home gem also skips.
2.36.16
- Welcome banner now actually appears for users with restored sessions. In v2.36.15 the banner was wired into
addProject, which fires once per restored gem during session restoration. The flag-set on the first call locked subsequent calls out, AND the banner was being fed into the first restored gem’s shard (hidden behind the other tabs, since restoration ends with the LAST gem selected). Moved the trigger into a post-restoration hook at +2.5s after launch. It reads the currently-selected session and feeds the banner there, so it lands in the tab the user is actually looking at on first launch of any new version.
2.36.15
- Onboarding nudges for the gem/shard mental model. crystl’s default first-launch state is an “unconfigured” gem at
$HOMEwith a single diamond shard. Previously nothing told users this was special, so they treated crystl like any other terminal and missed the central concept. Three small additions: (1) a one-time coloured welcome banner is fed into the first shard’s output explaining gems vs shards and pointing at the status-bar folder icon; (2) the folder icon next to the project label pulses gently while the gem is unconfigured, so the eye catches it (stops on click or when the gem becomes configured); (3) tooltips on both “+” buttons,new gem (project folder)on the top row,new shard (terminal session in this gem)on the shard row.
2.36.14
- Gem title no longer follows the active shard’s cwd.
hostCurrentDirectoryUpdate(which fires on every OSC 7 the shell emits, typically once per prompt) was rewritingproject.titleto the basename of the shard’s cwd whenever the gem didn’t have a custom name. That turned the gem identifier into a breadcrumb of “wherever I lastcd’d to”, so a shard wandering into~or auto-cd-ing into a worktree path would silently relabel the entire gem. The gem title is now a stable property set at init time and only changes on explicit user edit. Side effects (window subtitle, session cwd tracking, tab observers) still update on OSC 7 as before.
2.36.13
- Isolated shards refused when the gem is rooted at
$HOME. Some usersgit inittheir home directory (for dotfile management or otherwise). Creating an isolated shard on a home-rooted gem madeGitWorktree.createcorrectly produce~/.crystl/worktrees/<name>, but that pollutes the home git repo withcrystl/*branches and scatters shard cwds across the user’s entire home tree. Isolated shards on a home-rooted gem now fail fast with an explanatory error pointing the user at creating a gem for their actual project directory. - Loud yellow warning when any new shard is created on a home-rooted gem (isolated or shared). Home is almost always a misconfiguration regardless of shard type, so surface it instead of letting users discover it via downstream weirdness.
2.36.12
- Cursor is now visible whether GPU rendering is on or off. The Metal renderer already had a patch forcing the cursor to stay drawn regardless of Claude’s
\e[?25l(cursor-hide) spam during status-line redraws. The CoreText renderer didn’t,terminal.cursorHidden = truewould remove the caret view from its superview entirely, so users with GPU rendering disabled in General settings were typing into an invisible-cursor box while Claude was running. Mirrored the override into the CoreText path so the caret stays mounted regardless of what the terminal asks for. - GPU rendering toggle now states the restart requirement.
useMetalRendereris read once when a terminal session is initialized, so flipping it on a running shard has no effect, easy to misread as a broken toggle. Added a caption under it.
2.36.11
- Side quest tab no longer shows the PROJECT DIRECTORY picker or the gem-name row. Side quest connects two arbitrary shards across any gems and is directory-agnostic, it doesn’t operate inside a single directory. The picker was a leftover from the quest-tab layout and implied (incorrectly) that side quest was scoped to the launching gem’s directory. Both sections are now suppressed when the side-quest tab is active, and the panel shrinks to match.
2.36.10
- The quest setup panel’s PROJECT DIRECTORY picker now actually controls where the quest runs. Previously the picker accepted edits and looked editable, but for local quests every consumer downstream (shard cwd, isolated worktree base, party.json write, wizard join message, chat panel message reads, file watcher, context analyzer, v2 hook routing) anchored back at the gem’s own directory. So agents launched in the picked dir but the panel kept reading from the gem’s empty
.crystl/quests/, making quest features appear inert. Now a singleeffectiveQuestRootthreads through every read; the picker dir is the authoritative quest location. Persists to the gem’s.crystl/project.jsonso the anchor survives across app restarts. Open quests cd shards into the picked dir; isolated quests put worktrees under the picked dir’s git repo. - The redundant gem-name row in the panel header is gone when there’s nothing custom to show. A gem at
~with no custom name was rendering “chris” above a path field that read “~”, the same identifier twice. Now the row only renders when the gem’s title differs from its directory’s basename (i.e. a custom name was set). The path picker is the single source of truth. release.shnow tags locally and installs to~/Applicationsat the end. Local builds were stamping stale version strings intoInfo.plistbecause they read fromgit describeand the release tag only existed on the remote aftergh release create. Nowrelease.shcreates the tag locally before building, and copies the freshly-signed + notarized app into~/Applications/Crystl.appat the end so the installed version always matches what was just released.
2.36.9
- Quest setup panel header no longer overlaps itself. The gem icon and project name row was rendering inside the setup tab bar’s vertical range, causing the “side quest” tab label to collide with the project name (most visible when the project name was long like
promptreviews-web). Two builders in the panel layout used mismatched y-coordinate conventions (“decrement before placing” vs “place at y, advance after”); the gap step after the tab bar didn’t account for the gem row’s upward visual extent. Added the missing 17px so the row clears the tab bar cleanly. - Side-quest shard picker now shows the shard name on long project entries. The picker drew row text without a truncation paragraph style, so entries like
promptreviews-web / diamondclipped at the column’s right edge, hiding the shard name, which is the part users actually pick by. Switched to middle-truncation so both the project prefix (for context) and the shard suffix (for selection) survive on long entries.
2.36.8
- SGR rewriter no longer eats CPU on heavy output. The byte-level rewriter that protects against invisible-text-on-glass had been running on every single PTY byte since v2.36.0, copying each one individually into a fresh output array and scanning for escape sequences as it went. For interactive typing that’s free, but for streamed output (build logs, agent token streaming, file dumps) it was a measurable CPU tax that compounded with the App Nap suppression added in 2.36.4 to give a general “crystl is sluggish” feel. Two optimisations cut the cost to near-zero on the common case: a fast-path early return when the slice contains no ESC bytes at all (skips the entire walk and allocation entirely, this catches the vast majority of plain-text payload), and bulk-copying plain-text runs between CSI boundaries instead of per-byte appends. Correctness pinned by 19 SGR rewriter tests including two new ones for the fast path.
2.36.7
- Typed text now appears as you type inside Claude Code, not only after you hit Enter. Long-running symptom: characters you typed into Claude’s input box would be completely invisible until submit, at which point they’d all appear at once. Drag-selecting over the “empty” region revealed the bytes were there in the terminal buffer all along. The GPU just wasn’t painting them. SwiftTerm’s 60fps repaint throttle plus its dirty-row tracking can drop typed-input row paints under Claude’s rapid status-line redraw bursts, and the upstream race is the same on both the Metal and CoreText paths. Workaround: force a repaint after every PTY data chunk we receive. Bypasses SwiftTerm’s display queue entirely for the typing case. Marginal extra CPU under heavy output bursts, free for interactive typing.
- Glass readability: ghost-text grey vs typed-input white now properly distinguished. The renderer-level luminance floor was lifting everything near-grayscale below 235 to pure white, which destroyed Claude’s dim hint placeholder text (it should stay dim grey). The byte-level rewriter also had a “muted agent output → grey-170” tier that itself rendered as light grey on glass, the exact “light grey” complaint we were trying to kill. Fix threads the dim attribute from the SGR stream all the way through to the renderer: the rewriter keeps the dim flag in the output (was stripping it), drops the grey-170 tier entirely (everything it rewrites is now white), and the floor short-circuits on dim to preserve the rewriter’s intentional grey-120 ghost-text substitute. Result: typed input renders crisp white, ghost text renders dim grey, muted agent output renders white, saturated colours pass through untouched.
2.36.6
- Typed text actually renders as white now, the long-standing “everything looks translucent grey” bug is finally root-caused and fixed. Weeks of patches at the SGR-rewriting, luminance-floor, dim-attribute, and alpha-blending layers were all chasing a symptom downstream of the real problem. The actual cause: SwiftTerm’s Metal renderer rasterizes glyphs into a Core Text bitmap with macOS font smoothing enabled (
setShouldSmoothFonts(true)). Font smoothing is calibrated for dark-text-on-light-bg and bakes a luminance reduction directly into every glyph in the atlas. On crystl’s transparent glass background, that baked-in reduction made light text look uniformly grey regardless of what colour the agent emitted, what colour the shader received, or what we layered upstream. The grey was already in the atlas before anything else got a chance to touch it. Fix: smoothing off in the rasterizer; glyphs go into the atlas at full luminance and read as crisp white on glass.
2.36.5
- Typed input no longer turns light grey on later turns within a session. First message looked right, then somewhere around turn three your white input would render as grey for no apparent reason: same bytes, same agent, different colour. Two compounding causes. (1) A build could ship without the SwiftTerm fg luminance floor patch, falling back to SwiftTerm's
dimmedColor(towards: bg)which blends the foreground 50% toward the input box bg=(55,55,55) whenever the dim flag is set, so white becomes grey-155. The floor patch is now applied on every build. (2) The floor'sdim + bright → grey-120branch was actively harmful: the byte-level rewriter already substitutes explicit grey-120 for lone\e[2mghost-text, so any bright+dim pair reaching the renderer-level floor was a stuck SwiftTerm dim flag, and dimming bright text in that case produced exactly the user-visible bug. Removed the branch. Bright fg now always passes through regardless of dim state.
2.36.4
- Backgrounded terminals keep painting in real time. Previously, if you clicked away to another app while Claude was working, the terminal screen would freeze in place, bytes still arrived on the PTY read queue and updated the buffer in memory, but the queued display-refresh blocks didn't fire often enough to repaint. When you came back, the screen would snap forward in one jump to wherever Claude was now (often already finished), giving a "frozen but secretly working" experience. Cause: macOS App Nap throttling crystl's main run loop while another app was focused. Fix:
ProcessInfo.beginActivityfor the app's lifetime, same pattern Terminal.app and iTerm2 use. System sleep behaviour is unchanged.
2.36.3
- Typed input renders uniformly readable on glass, for real this time. The byte-level SGR rewriter was a losing battle against every variant agents emit; sequences split mid-word kept producing visible dim/bright transitions. The fix moves the floor to the SwiftTerm render layer: every painted glyph now goes through a luminance floor, so any near-grayscale dark foreground is lifted to readable at paint time, regardless of what bytes the agent sent or how they split across slices. Policy: dim + dark-near-gray → crisp white (typed input); dim + bright → grey-120 (ghost-text); no-dim + dark-near-gray → grey-170 (muted agent text); saturated colors pass through unchanged. The contract is pinned by a unit test suite that fails to compile if a SwiftTerm bump drops the patch.
2.36.2
- Cursor no longer disappears in shards running Claude Code. CC emits
\e[?25l(hide cursor) constantly during status-line redraws, and on stock SwiftTerm the Metal renderer skipped drawing the cursor for that frame, between redraws it never recovered, so the cursor visibly vanished. The cursor is now always drawn, regardless of CC's hide signal. The patch is now applied at build time viabuild.shinstead of being a stray uncommitted edit, so it survives any clean SwiftTerm re-resolution. - Patch: typed input now renders uniformly white instead of half-white-half-grey. v2.36.1 made some typed text crisp white but missed a redraw path where Claude Code splits the typed-input fingerprint across two SGR sequences (
\e[2mfirst, then\e[38;5;239mlater). The rewriter now tracks the dim attribute cumulatively across sequences, so the second SGR's near-grayscale dark fg is correctly classified as typed input and rewritten to full white, even at line-wrap boundaries where the split most often shows up. Also resolves the related "completely invisible character" cases.
2.36.1
- Patch: typed input now renders crisp white instead of muted grey. Claude Code wraps every typed character in a dim attribute plus a near-grayscale dark foreground; on the glass background that combination renders near-invisible without the SGR rewriter, and the rewriter's previous policy brightened it only as far as grey-170. The new policy detects the typed-input fingerprint (dim + near-grayscale dark fg) and rewrites the foreground to full white. Muted agent text (dark-gray fg without dim) still rewrites to grey-170 so it stays visually distinct, and the lone-dim ghost-text hint stays at grey-120.
2.36.0
- You'll know when an agent crashes inside an isolated shard. Previously when Claude (or any agent process) exited on its own inside an isolated shard, crystl silently auto-closed it and you were left wondering whether your work was saved. Now a non-blocking notification fires: “agent in {crystal name} exited, branch crystl/{name} kept with N commit(s)” (or “branch removed (no work to save)” if nothing was committed; appends “+ uncommitted changes” if you had untracked work). The user-driven close path with the merge prompt is unchanged.
- Every save button now flashes “saved” before dismissing. The pattern shipped in v2.35.0 for APIKeys and Facets settings is now extended via a shared helper to IconPicker, ClaudeTemplateEditor, StarterEditor, QuestPartyEditor, and QuestRoleEditor panels. Brief title flip + crystlAccent brighten + 1s dismiss everywhere a save closes a panel.
- Smarter resumption-burst suppression. The 30-second fingerprint rate-limit from v2.34.1 was imprecise, legitimate Stop hooks within the window could be suppressed and the resume storm could leak through if message text differed. The principled fix: when crystl auto-runs
claude --resumefor a session, it marks a 5-second window during which Stop hooks for that exact session ID are dropped at intake. The 30s fingerprint window stays as a safety net. Tunable viadefaults write com.crystl.app resumptionWindowSeconds -int 5. - Three more panel-monitor leak fixes. NewProjectPanel, HistoryPanel, and IconPickerPanel each now have a
deinitthat removes their global click monitors / NotificationCenter observers as a belt-and-suspenders fallback for misseddismiss()calls. - 57 button corner radii normalized. Off-spec
cornerRadius = 6sites bumped to the speccornerRadius = 8across 28 files (FacetBar, HistoryPanel, StarterEditorPanel, FileMaps, AgentFiles, Editor, Library, Helpers, DenialPanels, SettingsView, drag-drop rows, etc.). Small visual nits adding up to a more consistent feel. - All 6 audit hard-ceiling violators are now split. v2.35.0 covered four; this release finishes the job with AgentBlockLibraryPanel (686 → 350 + 4 extension files, with the Tier 3 9pt chip fix applied in flight) and AgentFileEditorPanel (635 → 346 + 4 extension files). Pure reorganization, no behavior change.
- +20 unit tests (378 → 398). New regression nets for the agent-exit message helper (7 tests) and the resumption-window suppression (13 tests on session-id windowing).
2.35.0
- Active gem highlights brighter on the rail. The previous selected vs unselected delta was dominated by the border; bg fill and icon alpha barely differed. Bumped selected bg alpha 0.25 → 0.42 and border alpha 0.6 → 0.9 so the active gem reads at a glance, and softened the inactive icon dim so they stay legible alongside it.
- Rail icons stay readable at low opacity. The transparency slider's
glass.alphaValuewas cascading to every tile, button, and icon, at the most-translucent end (alpha 0.2) tile icons dropped to ~13% effective alpha and were nearly invisible. Restructured so the glass blur sits at the back as a sibling of the interactive views, not their parent. Only the blur fades; tiles and icons stay at full alpha regardless of slider position. - Bridge token persists across crystl restarts. Every crystl restart used to write a fresh random token to
~/.crystl-bridge-token, which broke every SSH-tunneled shell because shell-init captures the token via env at spawn time. Now the existing token is reused (validated as 32- or 64-char hex; corrupt files regenerate cleanly). Tailscale and SSH-relay users no longer get 401s in every existing shell after a crystl restart. - Three more c9a3799-pattern panel races fixed. Same shape as the v2.34.0 fix: synchronously clearing
setupPanelinsidedismiss()chains dropped the strong reference beforeanimatePanelOut'sonDismisscould fire. Three additional sites covered (RailSettings toggle, RailSettings open path, AppDelegateonWillShowPanel). - New
--no-installflag forbuild.sh. Compile-only build that skips overwriting~/Applications/Crystl.app. Agents building from worktrees should use this, avoids the “crystl won't open” failure mode where the installed app'sBundle.modulepath was baked to a worktree that later got cleaned up. - +77 unit tests (301 → 378). New regression nets for
shellEscape(security-critical, was untested), MCPConfig merge (user-managed.mcp.jsonentries must survive sync), LicenseManager edge cases (.expired→.freetier), APIKeyStore Keychain round-trip (constructor-injected service name so tests can't pollute the real Keychain), and OSC 7770 parser (extracted into a pure function). - All 6 audit hard-ceiling violators split. ChamberSetupPanel, AgentFileEditorPanel+BlockView, FileLibrarySettingsPage, NewProjectPanel, AgentBlockLibraryPanel, AgentFileEditorPanel, all now under 400 lines, with the workhorse logic in
+Suffix.swiftextension files. Pure reorganization, no behavior change. Plus a Tier 3 UI hygiene pass across ~20 files (alpha-floor lifts, sub-10pt font bumps, ~50 inlineNSFontcalls migrated to Typography tokens,isHidden = true→layer.opacity = 0on glass-overlapping views).
2.34.1
- Patch: startup notification spam fixed. Restarting crystl with restored Claude sessions used to cause a flood of identical “command completed” panels. Root cause:
claude --resumere-fires Stop hooks for every prior assistant turn in the transcript, and crystl had no rate-limit on identical events at intake. v2.33.0's dismissal-suppression only kicked in after the user dismissed one. By then the burst had already stacked up. This patch adds a 30-second rate-limit on identical event fingerprints (same session, hook type, and message prefix), so the burst collapses into a single panel. Also catches tool loops firing the same Stop repeatedly, and any other source of bursty identical hooks.
2.34.0
- Worktree integrity hardening. Five fixes covering the audit's Tier 2 worktree cluster: replaced symlinks (e.g.
npm installoverwriting.claude/) are detected on session start and moved aside with a.crystl-replaced-{timestamp}suffix instead of letting per-shard config leak to main; the crystal-name validator is now actually enforced at every entry point that accepts a user/external name; the shard prompt body in autorun.sh is single-quote-escaped so a malicious branch name can't execute attacker-chosen shell; the crystal-name allocator considers allcrystl/*branches as occupied (not just orphans-with-work) so stale empty branches don't get silentlybranch -D'd; and remote SSH disconnect during close now preserves state so the orphan can be cleaned up on reconnect. - Two more c9a3799-pattern panel races fixed. Same shape as the gem-settings stuck-after-save bug:
openGemFromPickerandshowQuickModePickerwere clearing the panel's strong reference synchronously beforeanimatePanelOut'sonDismisscould fire. Now rely on the callback after the animation completes. - Terminal NSEvent monitor leak plugged.
removeScrollForwarding()was defined but never called, each session close left four global event monitors registered forever. Now called from the close paths and from a newdeiniton the terminal-view subclass. - Three
asyncAfterstrong-capture bugs fixed. The 0.3 to 0.5s asyncAfter blocks inopenSSHURL,showGemSettings, andsetGemApprovalModekept closed sessions alive just to feed a banner to a now-orphanedterminalView. Now[weak session]with a guard. - SGR rewriter hardening. The
pendingCSIbuffer is capped at 4 KiB so a malformed CSI from a buggy or hostile emitter (ESC[with no terminating final byte) can't OOM the process; on overflow the bytes flush to output as raw and the buffer resets. CSI parameter / intermediate / final phases are now walked explicitly per ECMA-48. build.shhard-fails when SwiftTerm sed patches can't apply. Previously a SwiftTerm refactor that renamedsnappedWidth/metalDirtyRange/ etc. would silently leave builds shipping unpatched code, regressing the “invisible text on glass” bug class. Now the build aborts loudly so the regression can't ship.
2.33.0
- Bridge security hardening. The in-process bridge that handles Claude Code's permission hooks now requires bearer authentication on all endpoints (previously loopback was exempt, which let any local process or DNS-rebinding browser POST decisions). Adds a strict
Hostheader check that rejects rebound hostnames and any request carryingOriginorReferer; opt-inbridgeRemoteAccessfor Tailscale / VPN / port-forwarding setups. Caps request bodies at 1 MiB with a 413 response before any body is buffered. Pairs each fix with a regression test in CI so the same drift can't slip back in. - Worktree data-loss prevention. Three close-time data-loss scenarios fixed: (1)
commitsAheadnow uses a stored fork point so worktrees with real commits don't silently report zero-ahead and get deleted when the project is on a feature branch; (2) untracked files in a worktree count as work to preserve, so agent-created files that were nevergit added are no longer force-removed on close; (3) corrupt-worktree recovery refuses to destroy a branch that has commits, so a transient lock file or permission flap can't trigger a silentgit branch -D. - scp upload paths shell-escaped. Remote file uploads via SSH now use a
cat | ssh ... > $(escaped path)pipe instead of rawscp host:path, so a remote path containing;or backticks can't execute on the remote host. - Dismissed notifications stay dismissed for 10 minutes. Identical events (same session, same hook type, same message prefix) are suppressed within the window. Protects against
claude --resumereplaying transcript hooks on session restore, pathological tool-loop floods, and any other source of bursty repeats. After 10 minutes a fresh occurrence re-fires normally. - SSH integration test harness + GitHub Actions CI. A sandboxed
sshdon127.0.0.1:2222backs end-to-end remote-session tests; CI runs both unit and SSH suites on macOS for every push. 31 new bridge regression tests cover the audit-touched paths so future security fixes can ship without breaking SSH features.
2.32.0
- Tool output and typed input render bright again on glass: 2.30.0 introduced a darker rewrite path for any SGR carrying the dim attribute, to keep Claude Code's ghost-text placeholder visually distinct from typed text. But Claude emits its tool output, git output summaries, and even your typed input as
dim + near-grayscale-dark fg, so all of that ended up rendered at gray-120 (visibly dull on glass). The dim-darken now applies only to the ghost-text case (lone\e[2m…\e[22mwith no explicit fg). Anything with an explicit fg rewrites to bright gray-170 as before.
2.31.0
- Gem settings panel closes again after save: clicking save in gem settings flashed the green “saved” state but then left the panel stuck on screen. The X, Escape, and click-outside were all silently dead. The onSubmit callback was clearing the panel's strong reference synchronously, so the panel deallocated before the post-save dismiss timer could fire, AppKit kept the window on screen with all its targets dangling. The strong reference now lives until
animatePanelOutactually completes.
2.30.0
- Claude Code ghost-text reads dimmer than typed text again: the placeholder hint (e.g. Try "write a test for <filepath>") was rendering at the same brightness as what you actually typed. The SGR rewriter that fixes invisible-text-on-glass was stripping the dim attribute entirely, including the lone
\e[2m…\e[22mblocks Claude uses for the ghost-text placeholder. Now dim-attributed text rewrites to a darker gray than regular grayscale text, and a lone dim sequence substitutes an explicit darker fg so the hint survives even when no fg color is set in the source SGR.
2.29.0
- Quest wrapper installs only when you summon a party: previously every non-diamond shard got the quest verbs and
claude()wrapper installed at creation time, even if you weren't running quest. On session restore the +0.8s inject lost the race toclaude --resumeand the bootstrap text (source /tmp/crystl-quest-…) ended up in Claude's input box. Now the wrapper is installed only when a quest party is actually summoned. Side quests already worked this way; nothing changes there. - Side-by-side builds no longer share config files: both were reading and writing
~/.config/crystl/for last-session, formations, facets, MCP catalog, file library, agent blocks, claude/starter templates, and bridge settings, so quitting one and launching the other restored the wrong workspace and overwrote the other's saved state. A second build now uses its own config directory. License key and hero-image cache stay shared (one Guild membership covers both, and the cache is just a CDN download).
2.28.0
- Readable input on glass: fixes invisible text when typing into Claude Code. The agent's input prompt was emitting 256-color and truecolor SGR codes that bypassed the 16-color palette floor and rendered as near-black on the transparent background, you'd type a sentence and only see it after pressing return. crystl now intercepts the PTY byte stream, parses CSI sequences, and rewrites near-grayscale dark foregrounds to a readable light gray. Saturated colors (red, blue, green) are preserved at any luminance.
2.27.0
- Close all gems: new
File → close all gemsaction for a one-click "start fresh". A single confirm dialog lists every running agent and unmerged isolated-shard branch across all open gems; on accept, the saved-session pointer is cleared so the next launch is empty, and a single fresh unconfigured gem replaces what was closed. Menu item disables itself when the only open gem is already fresh.
2.26.0
- End Quest: new
File → end questaction stands the party of agents down. A[quest ended]banner is bracketed-pasted into each shard, then every quest verb (quest_msg,quest_heartbeat,quest_task,quest_summary,quest_handoff,quest_announce,quest_claim,quest_note) is rewritten to a stub returning{"ok":false,"error":"quest_ended"}so already-running agents learn to stop reporting through their normal feedback channel. Works for local + remote (SSH) shards. The menu item is disabled when no shard is in a quest.
2.25.0
- Side Quest panel matches Quest UX: hero sidebar with crystal-color dots, name + gem, and a context lifebar;
— X joined the side quest —rows on open; CRT-fadecrystl side questlogo splash; cleaner header with identity moved to the sidebar; messages bottom-anchored like Quest. - Side-quest agents follow the protocol: the start banner now declares the rule explicitly: reply only by running
sidequest_msgvia the Bash tool, never as plain chat. Each routed message also carries a per-message reply reminder so the protocol stays in working context turn over turn.
2.24.0
- Glass-readable terminal palette: install all 16 ANSI colors with values tuned for the transparent background, eliminating dark/black text in TUI apps like Claude Code
2.23.0
- crystl://ssh URL scheme: open remote SSH sessions from other apps or scripts with
open "crystl://ssh/user@host/path"
2.22.0
- crystl:// URL scheme: open any project from other apps or scripts with
open "crystl:///path/to/project"
2.21.0
- Quest message injection: messages sent from the quest chat panel now correctly submit in Claude Code's terminal; fixes text appearing in the input buffer but never executing (Kitty keyboard protocol + bracketed paste)
2.20.0
- Quest message delivery: fixed
quest_announceandquest_taskwriting to an unwatched path; messages now reliably appear in the quest panel - SSH quest messages:
quest_msgnow resolves its log path at runtime so remote agents write to the correct location - Quest message persistence: messages sent while crystl is closed are replayed on next open via a cursor file
- Quest panel colors: agent names in the Tasks and Summaries tabs now render in their crystal colors
- Live summary feed: new summaries append in real-time when the Summaries tab is visible
- SSH hook reliability: quest verbs retry hook delivery 3 times with a warning on total failure
- Quest setup: tilde in project path field now expands correctly before git repo checks
2.19.76
- Gem settings close button: moved to top-right corner, removed invisible title bar that blocked clicks
2.19.74
- Scriptability API: local HTTP API (
/api/v1/) for programmatic control of gems, shards, permissions, and terminal content - crystl CLI: 11 commands:
status,gems,open,close,shards,send,screen,pending,approve,deny,token - SSE event stream: real-time notifications and permission request events at
/api/v1/events - Security: bearer token auth on all API routes, remote
/senddisabled by default
2.19.73
- Click-to-open fix: clicking file paths in Claude Code output now opens correctly instead of showing error -50
- Relative path resolution: relative paths resolved against session working directory, not app process directory
- SSH file click: file:// links over SSH download via SCP then open locally
2.19.72
- StopFailure notifications: glass panel appears on API errors: rate limit, auth expired, billing, server error, max tokens
- PermissionDenied panels: auto mode denials now show a retry/dismiss panel instead of failing silently
2.19.71
- Session resurrection: restores gems, shards, and Claude sessions on startup with zero clicks
- SSH session restore: SSH shards auto-reconnect, cd to remote directory, and resume Claude sessions
- Settings toggles: restore last session and resume Claude sessions toggles in General settings
2.19.69
- SSH hook fix: fixes permission auto-reject on SSH sessions caused by duplicate hook entries accumulating across builds
- Bridge failsafe: when bridge is unreachable, Claude Code now falls through to CLI prompt instead of silently rejecting
2.19.66
- Option+drag to select text: in tmux/vim, hold Option while dragging for native text selection, then Cmd+C to copy. Matches iTerm2/Alacritty/Kitty convention.
- OSC 52 clipboard bridging: tmux can now copy selection to system clipboard via escape sequences
- tmux drag forwarding: mouse drag events forwarded to tmux for click-drag selection highlighting
- One-time hints: brand blue hints for Option+drag and mouse mode on first use
2.19.63
- tmux scroll support: scroll events forwarded to tmux when mouse mode is on; one-time hint when it's off
- Drag to reorder gems: drag tab bar tabs with insertion indicator, rail tiles stay in sync
- 32 preset colors: doubled color palette with deep, rich, and earth tones; scrollable horizontally
- New gem panel reorder: identity at top, setup at bottom; consistent 16px header spacing
- Image drag: shows [image #] via native paste; window re-focuses after drag
- Bare URL detection: clicking domain.com/path opens browser instead of erroring
2.19.62
- Drag to reorder gems: drag tab bar tabs to rearrange project order, rail tiles stay in sync
- Image drag: dragging images into the terminal now shows [image #] instead of raw file paths
- Bare URL detection: clicking URLs like ads.google.com/path opens the browser instead of erroring
- SSH freeze fix: gem settings no longer blocks the main thread on stale SSH connections
- Close button fix: gem settings close button works reliably, brightens on hover
2.19.59
- Ecosystem-colored tags: block tags colored by platform: Swift orange, TypeScript blue, React cyan, Python green, and more
- Inline categories: category label next to block title instead of stacking vertically
- Tag-aware search: editor block search now matches tags and categories
- New block dialog: category dropdown + clickable tag chips for swift, macos, typescript, etc.
- Context load: lines: LINES column in token usage panel showing file line counts
- Optimizer animation: staggered fade-in on load and re-analyze
- 10 Swift/macOS rules: new library blocks for Swift development
2.19.58
- Save feedback: save buttons flash "saved" with bright green confirmation before reverting
- Explore tab: optimizer "map" renamed to "explore" with folder-open icon; "+" buttons on directories to add saved files
- Library hints: "?" buttons on library blocks show the explanation text in the preview area
- Agent block library: larger panel, proper search field styling, more preview space
- Blank rule removed: rule/skill menus no longer offer a useless blank heading option
- Gem panel fix: title text no longer clips descenders on "g" in "gem settings"
2.19.57
- Rule/skill picker: add rule and add skill show a menu of available blocks with content previews
- Drag to zones: dragging blocks from the library into the RULES or SKILLS zone sets the correct block type
- Source mode: raw markdown editor has a proper rounded input area
- Editor zones: rules/skills zones only appear when directories exist on disk
- SSH directory picker: cd command now sent to remote shell
- New gem layout: starter bundle section moved below icons, above MCP
2.19.55
- Add to project: library templates have a project picker to deploy files to any open gem
- Simple file editor: lightweight glass editor for .claudeignore, settings.json, and other non-block files
- Blank new files: new file templates start empty; starter kits keep the scaffold
- Custom filenames: templates can target any path, not just predefined agent file types
2.19.54
- 17 new optimizer checks: testing commands, code conventions, stack detection, verification gate, commit discipline, stale paths, cross-file consistency, gitignore misconfig, hooks, and permissions
- Weighted scoring: content quality weighted 3x higher than setup; AGENTS.md only penalizes multi-agent projects
- Copy for agent: export button writes optimization-report.md and copies a prompt to clipboard for pasting into Claude or Codex
- Bundle starters: new gems get .claudeignore and .claude/settings.json scaffolds automatically
- New blocks: Verification Gate, Commit Discipline, and Tool Restrictions available in the block library
- SSH gem settings fix: agent file checks now hit the remote filesystem instead of the local home directory
2.19.52
- Project Optimizer over SSH: health scores, gap detection, file creation, and the map/files views all read and write through the SSH connection
- File Library rules over SSH: .claude/rules/ listing, creation, editing, and deletion now work for remote projects
- File Maps panel over SSH: rule listing, file editing, add-file, and add-rule all SSH-aware
- Accurate context load for SSH: burn rate now correctly accounts for CLAUDE.md and AGENTS.md on remote hosts
- Gem settings CLAUDE.md detection: correctly detects existing CLAUDE.md on SSH projects
2.19.51
- SSH agent editor: agent files can now be opened, edited, and saved on SSH remote projects; rules and skills load and save correctly over SSH
- ProjectFilesystem: new internal abstraction routes all file operations to either the local filesystem or SSH, eliminating local-only guards throughout the app
- SSH agent files grid: gem settings now shows the correct agent files for remote projects
2.19.50
- Tabbed agent editor: tabs match the terminal gem tab style: separator line, active background, × close, + add, same fonts and spacing
- Close to delete: closing a tab permanently removes the agent file from disk (with confirmation)
- Add menu: pick any known agent type or enter a custom filename (cursor.md, aider.md, etc.)
- Auto-detect: AGENTS.md, GEMINI.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md open automatically as tabs
- Gem settings grid: agent files shown as a clean two-column grid, no false positives from unrelated .md files
2.19.46
- Rules divider: blue zone in the CLAUDE.md block editor; blocks below become individual .claude/rules/*.md files
- Skills divider: purple zone below rules; blocks become .claude/commands/*.md slash commands
- Drag across zones: move content between CLAUDE.md, rules, and skills by dragging blocks across dividers
- Auto-load: existing rule and skill files load into their zones when opening a project's CLAUDE.md
- PLANS.md: new file type for OpenAI Codex execution plan templates
2.19.45
- GEMINI.md support: create and manage Google Gemini CLI instruction files
- Optimizer line count: flags CLAUDE.md over 200 lines with suggestion to split into rules
- Map view add file: "+ add file" button opens file chooser panel from any directory
- Map view add rule: "+ add rule" button with name and path-scope dialog in .claude/rules/
2.19.44
- File chooser panel: glass panel with icons and descriptions for creating project files (CLAUDE.md, AGENTS.md, codex.md, .cursorrules, and more)
- CLAUDE.md w/rules: recommended option that creates CLAUDE.md + .claude/rules/ directory together; badge in the chooser
- Claude rules tab: manage .claude/rules/*.md files in File Library settings with name and path-scoping support
- Line count bar: CLAUDE.md editor footer shows live line count; turns yellow at 150, red over 200
- Codex.md templates: dropdown in New Gem panel for selecting codex.md templates
- Separate skill sections: Claude Skills and Codex Skills as distinct sections in New Gem panel
2.19.41
- Optimizer SSH guard: "optimize" button is now hidden for SSH gems; the analyzer reads local filesystem only and would scan the wrong directory for remote sessions
2.19.40
- SSH show button fix: approval panel "show" now correctly navigates to the originating shard for port-forwarded SSH sessions (connections without user@host format)
2.19.39
- Formations fix: project names now restore correctly for SSH gems; port-forwarded sessions were silently dropping names on save
2.19.38
- Skills import fix: importing from the skills library now installs files directly to
~/.claude/commands/; previously nothing was written to disk - Section header UX: block editor section rows are now inline-editable (no more double-panel expand)
- File Maps: hide non-existent instruction files; add library shortcut at bottom
- Gem settings panel: refactored, adds optimizer shortcut in edit mode
2.19.37
- Remove File Maps window: per-project agent setup coming as part of gem settings
2.19.36
- File maps fix: panel title no longer overlaps traffic light buttons
2.19.35
- Rename "crystl codex" to "crystl library" throughout
2.19.34
- File Library: new settings page with a block-based CLAUDE.md editor, Claude skills manager (
.claude/commands/), and Codex skills manager (~/.agents/skills/) - Block editor: compose instruction files from reusable blocks; drag to reorder, inline heading edit, save any section to your block library
- Guild: browse 200+ blocks & skills: import agent blocks (rules + workflows), Claude skills, Codex skills, and file templates directly from the crystl.dev library
- 7 instruction file types: expanded support for CLAUDE.md, CLAUDE.local.md, AGENTS.md, codex.md, .cursorrules, copilot-instructions.md, .windsurfrules with type-specific scaffolds
- File Maps panel: browse agent config files across all your projects from the Window menu
- Image drag-drop fix: drop now only intercepts in remote (SSH) sessions; local sessions pass through to Claude Code natively
2.19.33
- Remote session fix: gem settings save no longer sends
cd+clearto the terminal when connected via SSH or running a process - Facet bar redesign: unified segments with inline dropdown triangles, diamond settings icon with hover glow
2.19.32
- Context Map: new settings page for viewing agent config files across all projects. Drillable subdirectories, color‑coded type badges (Claude, Codex, Cursor, Aider, Copilot, Windsurf), coverage bars, discovered projects, and tracked files reference
- SSH config alias fix: bare hostnames like
ssh myserverare now correctly detected for image paste, drag‑and‑drop, and remote features - Quest settings rearranged: user character is a compact bar on the left, heroes moved to right column
- DM unread indicators: dot on DM channel pills, badge on dms toggle, distinct two‑note DM sound
- Gem settings accordions: collapsible PROJECT FILES, SKILLS, MCP sections with Lucide chevrons
- Renamed starter files → agent files
2.19.31
- SSH host parsing fix: port‑forwarded connections (
-L,-R,-D) no longer misdetect the forwarding spec as the hostname. Fixes SCP uploads, drag‑and‑drop, and remote features for port‑forwarded SSH - Paste fallback: if SCP fails, the local file path is pasted instead of silently dropping
- DM unread indicators: unread dot on DM channel pills, badge on “dms” toggle button
- DM sound: two‑note ascending ping, distinct from the main chat tick
2.19.30
- File logger: crystl now writes to
~/Library/Logs/Crystl/crystl.logwith 5 MB rotation. Bridge and paste diagnostics logged for easy debugging
2.19.29
- Hardened image/file paste: checks 6 pasteboard types for cross‑macOS‑version reliability, adds NSImage fallback for non‑standard clipboard managers, and diagnostic logging for SSH upload debugging
2.19.28
- Quest report export: export button in the quest panel generates a timestamped Markdown report with party roster, message counts (main + DM), token usage per shard, user prompts, git diff, and chat log
- SSH image/file paste: Cmd+V of images and files now uploads via SCP for remote sessions, matching drag‑and‑drop behavior
2.19.27
- Smart image/file paste: Cmd+V of files from Finder pastes full shell‑escaped paths instead of bare filenames. Cmd+V of screenshot image data saves to a temp PNG and pastes the path. Regular text paste is unchanged
- Retooled demo: the in‑app demo now showcases all panel types in sequence: permission panel, question notification, and multi‑question series with architecture questions
2.19.26
- Collapsible accordion sections: PROJECT FILES, SKILLS, and INCLUDE MCP in gem settings are now collapsible with Lucide chevron disclosure icons. Sections default to collapsed for a compact panel. Insert buttons use brand blue with hover state
2.19.25
- Marquee scroll: hovering a gem tab with a truncated name scrolls the text left to reveal the full name
- External notifications dropped: notification hooks from Claude Code running outside crystl are now silently ignored, preventing spurious “Claude is waiting for your input” panels
2.19.24
- Scrollable tab & shard bars: gem tabs and shard pills now scroll horizontally when they overflow. The + and split buttons follow naturally after the last item, pinning to the right edge only when overflow occurs. Quest and isolation buttons stay visible
- Quest join sound fix: the “join” chime no longer plays when adding shards outside of an active quest session
2.19.23
- Screenshot bar: a thumbnail strip at the bottom of the window showing your recent screenshots (powered by Spotlight). Drag a thumbnail into the terminal to paste the file path, or double‑click to open. Toggle via View > screenshot bar (⇧⌘S). Visibility persists across restarts
- View menu fix: removed duplicate “increase font size” entry
2.19.22
- Quest directory fix: all four quest modes (local/remote × open/sealed) now use the directory shown in the setup panel. Quest setup defaults to your current working directory instead of the gem root
- SSH cwd tracking: remote shells emit OSC 7772 via precmd hooks (zsh + bash) so crystl always knows the remote working directory. Replaces the broken
pwd‑over‑new‑channel approach - SSH exit detection: disconnecting from SSH clears remote state so quest setup correctly switches back to local mode
- Local directory picker: quest setup now has a browse button for local projects, using the existing glass directory picker
- Join messages: remote quest shards now show “has joined your party” in chat, with dedup guard to prevent double posts
2.19.21
- Quest v2 Phase 2: SSH remote parity complete: all v2 verbs install on remote shards, hooks mirror state back to crystl, local state is uploaded to remotes, and remote shards get v2 prompts. New ambient feed UI adds tasks, summaries, and per‑shard progress tabs to the quest panel
- SSH panel routing fix: all panel types (notification, approval, denial, ask‑user) now use shard‑aware project matching so SSH gems sharing the same local path route to the correct project
- Tasks tab fix: JSON key mismatch (
task_idvsid) caused silent decode failure and empty tasks tab - Shard pulse: working shards now pulse more visibly (0.3‑1.0 range); selected shard’s underline breathes when its agent is active
- Context health bar fix: dev mode synthetic data no longer corrupts real agent metrics
2.19.20
- New gem name fix: clicking “+” in the tab bar no longer inherits the name, icon, and color from a previous gem's config at
~/.crystl/project.json - SSH formation loading: the
cdinto saved remote directory now waits for the actual SSH connection (OSC 7771 signal) instead of a blind 1.5‑second timer, so slow networks and password prompts no longer lose the command - Multi‑SSH shard fix: shard restoration now tracks project indices directly instead of path matching, fixing wrong‑project targeting when multiple SSH gems share the same local path
2.19.19
- Crash fix: crystl could crash with a
SIGABRTinSessionBarView.drawwhen CoreText'sTAttributes::ApplyFontencountered a nil value while processing SF Mono's variable‑font feature dictionary. The two shard‑label fonts are now cached as static stored properties and pre‑fetched before the draw loop, preventing any race between first‑load and the 20 Hz pulse timer - Quest verbs: added
quest_claimandquest_announceverbs; improved prompt quality and question detection accuracy
2.19.18
- Quest inter‑shard communication fix: the status‑file hint pointed agents at
.crystl/quest/v2/messages.jsonlbutquest_msgwrites to.crystl/quest/messages.jsonl, so agents always saw an empty file and couldn't read each other's messages. Fixed the path so agents can now read the shared quest log - No more duplicate messages: the file watcher was re‑writing messages it read from disk back into the JSONL file with a new UUID, doubling every entry. Now passes
fromFile: truethrough the protocol so file‑sourced messages skip the write‑back - quest_msg confirmation output:
quest_msgnow prints{"ok":true,"id":"..."}on success, matching the v2 verb convention so agents can verify delivery - Recon‑first quest protocol: agents are now instructed to read
messages.jsonland survey the repo before writing any code, preventing incompatible tech‑stack decisions. Key decisions (architecture, framework choice) are posted immediately so teammates can align - Click‑to‑open refactor: replaced custom mouse‑event click‑to‑open with SwiftTerm's native link system
- Notification shard resolution: notification hooks now resolve the correct shard via cached
session_id
2.19.17
- Per‑shard identity fix: message sender attribution, working/ready state, and context health metrics were all routing to the wrong shard when
CRYSTL_SHARDwas inherited into crystl's own environment (e.g. launching crystl from inside another crystl tab). Fixed with two‑layer defense at the env‑inheritance layer so it can't regress silently - Context health bar rebased on usable budget: the bar used to count Claude Code's fixed startup cost (system prompt, tool definitions, walked‑up CLAUDE.md files) against the shard's budget, so it could drop to yellow on the very first turn with no work having happened. Now uses the first recorded turn as a baseline and measures only real per‑turn work accumulation.
turnsRemainingalso estimated against usable budget - Question detection false‑positives: the trailing‑decoration strip was chewing past closing code fences and JSON terminators into embedded
?characters inside string literals, lighting up “has a question” cards on turns where the agent wasn't asking anything. Now scoped to the last non‑empty line of the message so structural delimiters can't trigger
2.19.16
- Quest v2 operational verbs: four new shell commands for shard‑to‑shard coordination.
quest_heartbeatwrites live status + current task + optional blocker.quest_taskdelegates async work to another shard with ownership tracking.quest_summarycheckpoints progress on a task without handing off.quest_handoffhands off the full task with decisions / blockers / next steps, optionally auto‑assigned. Each verb ships as a bash script installed into every local shard'sbin‑<shard>/at session start and returns structured JSON with exit codes for scripting - Structured quest state files: new
.crystl/quest/v2/layout with per‑shardprogress/,status/,tasks.json, and an append‑onlysummaries.jsonl. crystl writescontext_pctinto each shard's progress file from hook metrics, so teammates cancatthe files for live situational awareness without replaying the chat - Healer context‑watching: shards with the Healer role now get a system‑prompt addendum that tells them to read the progress files during their own turns and nudge any shard below 20% context toward a handoff. Pure prompt‑driven, only fires when a healer is actually in the party, no background daemon
- party.json migration: the quest‑related UserDefaults keys (party composition, per‑shard role overrides, user character sheet) now dual‑write to a single
party.jsonfile under each project's.crystl/quest/v2/. First‑run bootstrap handles the migration from UserDefaults; a corrupt file regenerates from UserDefaults automatically - System Prompts page: new read‑only cards for the quest v2 operational verbs, the healer addendum, and a local/remote split on the status‑file hint so remote SSH shards no longer get pointers to files that don't exist on the remote host
- Settings subtitle slot: the System Prompts page copy now wraps cleanly under the page title instead of being jammed into the page body
2.19.15
- Fix: false‑positive “has a question” cards: the Stop‑hook question detector was matching any
?in the trailing 60 characters, so it lit up on turns that contained a markdown link query string (?foo=barinside a URL), a ternary in a code fence, or a rhetorical aside. It now requires the final meaningful character (after stripping trailing whitespace + markdown decoration) to be?, and routing + display share the same helper so they can’t disagree. Regression coverage added - Quest rename: commander → user across the quest panel, a new read‑only System Prompts settings page, and
PromptTemplatesextraction for the quest prompt assembly
2.19.14
- Session‑ID panel routing: floating approval, ask, notification, and process‑finished cards now route show buttons back to the originating shard by its UUID. Survives shard renames and empty‑cwd edge cases that previously stranded the old cwd/name matching
- Hook‑activity grace window: the agent monitor no longer flips shards to idle while Claude is mid‑stream. Non‑Stop hooks extend a 45 s grace window during which CPU‑based idle detection is suppressed, so streaming LLM turns stay marked working
- Turn‑start hooks:
PreToolUseandUserPromptSubmitare now installed alongside the existing hook set, so the shard pulse animation lights up the instant a turn starts rather than waiting for the first tool to finish. Projects missing these hooks are auto‑upgraded on next launch - Terminal font shortcuts: ⌘+ / ⌘− / ⌘0 to increase, decrease, or reset the terminal font. Persisted across launches and applied live to every open session
- Join crystl Slack: Help menu now has direct links to join and sign in to the crystl Slack community
- Quest panel live relayout: swapping parties in the quest setup popup rebuilds the panel in place without flickering the anchor, and a close button lets you bail without clicking outside
- Tab / shard label legibility: tab labels bumped to 12 pt and shard labels to 11 pt for crisper rendering at the monospaced sizes the UI actually uses
2.19.13
- Question notifications work over SSH: Stop hooks from SSH shards now get the same “has a question” cards as local shards. Previously SSH sessions only got the 60 s-delayed idle fallback because the remote transcript file was unreachable from the local bridge
- Remote augment script: the shell-integration installs a tiny
~/.claude/crystl-augment.pyon each remote host and pipes Stop payloads through it before posting to the bridge. The augment parses the transcript JSONL in place and injectslast_assistant_message, so the local bridge sees the same shape whether the session is local or remote - Safe on error: non-Stop hooks pass through untouched and any augment error falls back to the original payload, so a broken transcript can't break the hook chain
2.19.12
- Shard-aware “show” buttons: approval, ask-user, notification, and process-finished cards now remember which shard raised them, so clicking show takes you to the exact session instead of just the project tab
- Question notifications: when Claude ends a turn with a question, a green “has a question” card appears with side-by-side dismiss / answer buttons. Answer focuses the shard and clears the card in one click
- Transcript-driven Stop hook: the last assistant message is now parsed out of the transcript JSONL, since Claude Code's Stop payload omits
last_assistant_messageby default - Question toggle override: Stop-with-“?” bypasses the Stop notification toggle, so turning off generic “Claude finished” cards still lets explicit questions through
- Question dedup: Claude Code's idle
Notificationhook is deduped against the Stop hook via a 120-second per-session window. One event, one card
2.19.11
- Hero health bars: hero health bars in the quest panel now actually reflect context usage. Previously every shard stayed at 100% because session metrics were being attributed to the wrong shard
- Context load button: the "turns left" button now appears after 3 Claude turns as intended. Same root cause: turn metrics were landing on the wrong session, so the visible shard's count stayed at 0
- Shard-routed metrics: the
X-Crystl-Shardhook header is now threaded through session-metrics and hook-activity callbacks, so sessions match by name instead of the ambiguous cwd fallback - Dev-mode fix:
CRYSTL_DEVsynthetic context data now actually injects (was gated on a turn counter that never advanced)
2.19.10
- Quest DM delivery:
quest_msg "shard" "text"now actually delivers the message to the target shard's terminal instead of only creating a side-channel in the UI - Quest party editor: prevented adding the same crystal twice when building a quest party
- AskUserQuestion routing: questions from Claude Code now route to the input panel instead of getting auto-approved into a phantom empty answer
- Bridge binds loopback by default: the hook bridge no longer listens on all interfaces out of the box; Tailscale/VPN users can opt in via
bridgeRemoteAccess - Keychain-backed API keys:
ANTHROPIC_API_KEY,OPENAI_API_KEY,GEMINI_API_KEY, andOPENROUTER_API_KEYare stored in macOS Keychain, never on disk in plaintext - Hardened license validation: tighter checks in
LicenseManagerto prevent tampering - MCP import validation: imported MCP server configs are validated before being written to
.mcp.json - Command history + remote session hardening: shell integration, worktree setup, and SSH bridges no longer shell-interpolate untrusted input
- Worktree reliability: detached-HEAD detection, accurate dirty-state checks, and better error messages when
git worktreeoperations fail - Bridge server fixes: timer scheduling order, FileHandle guard, and approval-panel cache no longer race on startup
- UI consistency pass: typography tokens across the app, text alpha floor enforced (no more disappearing labels on translucent glass), consistent corner radii, and live-reactive window opacity
2.19.9
- Correct shard in notifications: stale
CRYSTL_SHARDenv vars from orphaned Claude Code processes no longer mislabel which shard needs attention; the hook header is validated against the project's current sessions - Instant library imports: prompts, heroes, templates, and skills imported from the library panels appear in settings immediately instead of requiring a page switch
- Facets: no duplication: prompts live in exactly one place: the slot OR the library list, never both
- Facets: edit in slot: click a prompt in a slot to edit it; the × now dismisses back to the library (delete only happens on the library side)
- Facets: glass dropdown: triangle dropdowns on facet pills now use the crystl glass aesthetic instead of the default gray menu
2.19.8
- Remote git worktrees: create isolated shards on remote servers via SSH with full merge/rebase/close lifecycle
- Shard directory inheritance: new shards inherit SSH session and working directory from the current shard
- Formation SSH restore: formations save and restore SSH host, remote working directory, icon, and color per gem
- Remote orphaned branches: Isolation panel shows remote branches for reopening
- Fixed remote notifications: removed invalid hook types that broke Claude Code hook validation on remote machines
- Fixed paste highlight: pasted text no longer shows as black-on-black in the terminal
- Per-gem approval: auto-approval now works correctly for SSH and worktree sessions
- Dual-build isolation: two builds no longer interfere when running simultaneously
2.19.7
- Reliable formations: backup before save, auto-restore from backup on corrupt data, error dialogs for missing paths instead of silent failures
- Path normalization: formation paths resolve symlinks, expand tildes, and strip trailing slashes for reliable matching
- Overwrite & rename safety: warns before overwriting an existing formation, prevents duplicate names on rename
- SSH auto-tunnel on by default: new users get the SSH reverse tunnel without needing to find the setting
2.19.6
- Formation SSH auto-reconnect: formations save SSH hosts per gem and shard, auto-reconnect on load with a single confirmation prompt
2.19.5
- Full SSH feature parity: session history, command logs, context load, starter files, and quest prompts all sync to remote over SSH
- Question detection fix: long messages no longer lose the trailing ? that triggers question notifications
- Security hardening: sanitized hero names, auth on unknown connections, restricted file permissions on remote config
2.19.4
- SSH session tracking: notifications and approval panels show the correct project even with many remote SSH sessions open
- Party dropdown roles: hero list shows role names alongside character names
- Custom hero creator: single-panel creation with name, role, personality, instructions, stats, and model (Guild)
2.19.3
- Quest over SSH: quest messages now relay through the bridge on remote sessions
- Reliable shard names: notifications always show the correct shard context, even with subdirectory paths or before agent detection
- International keyboards: auto-detects Nordic, German, French, and other layouts; disables Option-as-Meta so @, €, {, } work out of the box
2.19.2
- SSH notifications for Tailscale/VPN: hook relay now auto-detects remote client IP, bypassing broken SSH port forwarding on Tailscale SSH and VPN setups
- Bridge address override: optional field in Settings > Claude for manual bridge address configuration
2.19.1
- Imported heroes visible: heroes imported from the Hero Library now appear in the YOUR HEROES list, party editor, and add-member dropdown
- Hero portraits: portrait images now download for all heroes, not just built-in catalog entries
2.19.0
- Custom API keys: add arbitrary env vars for any AI provider (Mistral, Groq, xAI, etc.) from the API Keys settings page
- Code quality overhaul: split ChamberSettingsPage into 5 files, fixed 22 review issues including thread safety, observer leaks, accessibility labels, and Typography token adoption
- UI polish: roll dice button with hover state, improved stat stepper arrows, settings spacing fixes across general, claude, and quest pages
- Scribe hero: new Documentation specialist hero in the quest catalog
- Notification fixes: notifications no longer misattribute to the wrong project, shard colors scoped correctly
- License key display: long keys are truncated to a short preview after pasting
2.18.1
- Close warnings: warns before closing shards, gems, or quitting when processes are still running; worktree merge dialogs now also show running process info
- Dock badge: pending approval count shown on the dock icon with bounce on new requests
- Formation shard saving: formations can optionally save open shard state (crystal names, isolation) and restore them on load
2.18.0
- Starter files in gem panels: new gem panel shows CLAUDE.md checkbox+dropdown, separate INCLUDE FILES and SKILLS sections with per-file control
- Edit mode project files: gem settings shows exists/insert status for configured starters; insert buttons write files immediately without affecting save
- Skills section:
.claude/commands/starters are split into their own SKILLS section in both new gem and edit mode - Skills Library: browse and import skills from the skills library in starter settings
- Panel coordination: rail panels (new gem, open picker, gem settings) dismiss each other when opening
- Library upgrade prompts: template, hero, and prompt library panels show Guild upgrade prompt on auth errors
2.16.0
- Token usage panel: per-shard bar chart showing input tokens per turn with projected future turns and burn rate
- Turns remaining: estimated turns left before hitting the context window ceiling, shown in the status bar
- Per-turn cost breakdown: table showing conversation growth and fixed costs (CLAUDE.md, settings) consumed each turn
- Model detection: reads the model ID from Claude Code transcripts for accurate context window sizing
- Quest sidebar turns: each agent in the quest sidebar shows estimated turns remaining; click to open their chart
- JSON export: writes
.crystl/context-load.jsonfor healer and agent consumption
2.15.0
- Quest: multi-agent coordination: summon a party of Claude Code agents with an IRC-style chat panel for real-time coordination
- Party templates: 10 hero archetypes (wizard, ranger, rogue, healer, etc.) with customizable roles, personalities, and RPG stats
- Per-hero model picker: choose Opus, Sonnet, or Haiku per role with smart defaults (Opus for research, Haiku for QA)
- Sealed quest mode: each hero works on its own git branch via worktrees, eliminating file conflicts between agents
- Context health bars: monitor each agent’s remaining context window in the quest sidebar
- DM channels: direct message individual agents via @mentions
- Commander profile: your own character sheet that shapes how agents interact with you
- Hero system reference: stat band chart in settings explains how STR/INT/WIS/DEX affect agent behavior
- Parallel message delivery replaces slow sequential queue
- File locking on quest message log prevents corruption from concurrent agents
- Quest setup panel with radio buttons, risk badges, and git repo detection
2.14.5
- Marquee scroll on hover: truncated text in approval and notification panels auto-scrolls when you hover to reveal the full content
- Shard crystal colors: notification headlines use the shard’s actual crystal color instead of generic tint
- Approval panels stay visible: timeout extended from 60 seconds to 5 minutes so panels don’t disappear before you act
- Duplicate permission notifications suppressed when approval panels are already showing
2.14.4
- Personified shard notifications: approval panels show “diamond wants to edit a file” instead of bare tool names like “Bash”
- Shard identity in notifications: notification headlines use the shard name (“diamond has a question”) instead of “Claude”
- Cleaner notification stack: redundant “needs your permission” notification cards no longer appear alongside approval panels
- Centralized Typography system with semantic font tokens across all panels and settings
2.14.3
- Full Disk Access prompt: guides new users to grant FDA on first launch, preventing repeated macOS permission dialogs
- Codesigned dev builds: build.sh now signs with hardened runtime to match release builds
- Fix duplicate shard names: auto-naming skips crystal names already used by active sessions or existing worktrees
- Fix worktree reopen: reopening an already-open worktree switches to it instead of creating a duplicate
- Dismiss settings flyout when opening gem settings panel and vice versa
2.14.2
- Per-project approval mode: set Manual/Smart/Auto Approve per gem
- Click selected rail tile to open Gem Settings panel
- Fix icon category tab clicks in scrolled positions
- Global approval flyout: renamed header, divider before Pause All
- Terminal readout when approval mode changes
2.14.1
- Clickable links: URLs in terminal output underline on hover and open in browser on click (no Cmd key needed)
- Arrow cursor: cursor changes from I-beam to arrow when hovering over clickable URLs or file paths
- Lowercase labels: History, Settings, and Isolation buttons now use lowercase styling
- Removed broken glow/shimmer effects and non-functional shard rename
2.14.0
- Gem toolbar capsule: History and Settings buttons grouped in a frosted glass pill with the project’s Lucide icon alongside
- Connected facet pills: facet action buttons share a single connected pill with hairline dividers
- Facet label truncation: segment width capped at 120px with ellipsis for long labels
- Nature & Animals icon categories: split into separate categories in the icon picker; added snowflake, waves, and wind icons
- Scrollable icon category tabs: all categories reachable via horizontal scroll
2.13.8
- Multi-question AskUser panels: prev/next dot navigation in a single panel; answers preserved when navigating back and forth
- Always-visible cursor: cursor stays visible while Claude Code runs, matching Warp behavior
- Sound settings: separate sound pickers for Denied and Question panels in Settings > General > Sounds
- Panel consistency: all panels now show project icon, name, shard name, and Show button with standardized spacing
- SSH hook timeout bumped to 3s for more reliable remote notifications
- PermissionDenied hook added to remote setup command
2.13.7
- SSH file relay: drag/drop or paste images into SSH terminals; files are SCP’d to the remote automatically via ControlMaster
- Remote click-to-open: clicking file paths in SSH sessions downloads the file via SCP and opens it locally
- Remote gem config: CLAUDE.md, starter files, and .mcp.json are written to the remote filesystem when configuring SSH gems
- Bridge relay endpoints:
/relay/image,/relay/open,/relay/clipboardfor remote-to-local communication - AskUserQuestion panels: now show full question text with numbered options for multi-question format
- Fix answer passthrough so Claude Code receives multi-question selections correctly
- Auto-sizing panel height based on question content
2.13.6
- Auto SSH relay: when Auto-tunnel is enabled, crystl automatically installs Claude Code hooks on the remote machine via SSH RemoteCommand (no more manual paste)
- PermissionDenied panels: when auto mode denies a tool, an orange floating card appears with Retry/Dismiss buttons
- AskUserQuestion panels: Claude's questions appear in a floating glass panel with scrollable text and an input field
- Styled DMG installer: proper drag-to-install layout with icon positioning
- Both new panel types toggleable in Settings → Claude → Notifications
2.13.5
- Top-mounted Crystal Rail: the rail can now sit at the top of the screen as a horizontal bar with tiles laid out left-to-right
- Drag-to-snap: grab the rail and drag it to any screen edge (left, right, or top) to reposition instantly
- Two-column panel layout: in top mode, notifications stack to the left of the bar and approvals to the right
- Rail Position setting updated with three options: Left, Right, Top
- Fixed icon picker ignoring right-side rail position
2.13.3
- SSH tunnel support: toggle in Settings → Claude auto-forwards port 19280 so approval panels work on remote machines via SSH
- Remote hook setup: "Copy Remote Setup Command" button installs Claude Code hooks on remote machines with one paste
- Paste visibility fix: pasted text is now readable on dark backgrounds (disabled zsh paste highlight, remapped ANSI black)
- Cursor restore: auto-restores cursor after Claude Code's spinner; Cmd+Shift+R for manual reset
- SSH hint: one-time yellow tip when you first run
sshwithout the tunnel enabled - No more Node.js: the bridge is now a native Swift HTTP server running inside the app. Zero external dependencies.
- Instant approval panels: direct callbacks instead of HTTP polling, no more latency
- Auto-configure Claude Code hooks: hooks are written to
~/.claude/settings.jsonon first launch - Facet Inserts: configurable pill buttons below the terminal that send text to your session on click (Settings → Facet Inserts)
- Prompt Library: Guild members can browse 70+ prompts from crystl.dev and import them as facet inserts
- Standalone Prompt Browser: Window → Prompt Library opens a separate browsing window with search and category filtering
- Universal binary: runs natively on both Intel and Apple Silicon Macs
- Proper code signing: inside-out signing with entitlements, notarization stapled to .app
- Single-instance enforcement: prevents duplicate windows and approval panel races
- Claude settings: Effort Level and Default Mode now properly saved
- Consistent glass opacity on all panels (Isolation, History)
- Non-zsh shell notice for fish/bash users
- Old Node.js bridge automatically cleaned up on upgrade
2.11.0
- Isolation panel: glass dropdown in the shard bar for worktree management: create, reopen, merge, and rebase isolated shards from one place
- Reopen worktrees: orphaned
crystl/*branches with commits or uncommitted changes appear in the Isolation panel for one-click reattachment - Worktree safety: existing intact worktrees are reused on reopen instead of being force-removed, preserving uncommitted changes
- Removed redundant status bar worktree button
- Fixed focus restoration after Isolation panel dismiss and merge error dialogs
2.10.0
- Isolation panel: new glass dropdown in the shard bar for worktree management: create, reopen, merge, and rebase isolated shards from one place
- Reopen worktrees: orphaned
crystl/*branches with commits or uncommitted changes appear in the Isolation panel for one-click reattachment - Merge-on-close prompt: closing an isolated shard with commits now asks: Merge to Main, Keep Branch, or Discard
- Gem close protection: closing a gem with unmerged worktree branches prompts to keep or discard all branches
- Agent guardrails: worktree agents are explicitly instructed not to merge, cherry-pick, or rebase to main; crystl handles branch integration
- Worktree safety: existing intact worktrees are reused on reopen instead of being force-removed, preserving uncommitted changes
- Directory picker search fix: search field now accepts keyboard input and mouse clicks
- Bridge status redesign: replaced green dot with contextual "Bridge disconnected" warning button with troubleshooting popover
- Isolated shard fix: fixed zsh parse error when
claudeis aliased in the user's shell
2.9.0
- Bridge health check: one-time alert on launch if Node.js is missing or bridge can't connect, with clear instructions
- Bridge status indicator: warning appears in status bar when bridge is disconnected with clickable troubleshooting
- Code signing and notarization: releases are now signed with a Developer ID certificate and notarized by Apple
2.8.0
- Shard context for Claude Code: isolated shards inject branch name, worktree awareness, and parallel agent guidance into Claude Code's system prompt
2.7.0
- Worktree auto-setup: isolated shards auto-detect package managers (16 supported), install dependencies, and symlink .env files
- Custom setup commands via
setupCommandin.crystl/project.json - CLAUDE.md templates: pick from saved presets when creating a gem
- Template management in Settings → Starter Files
- UI fixes for Gem Settings panel spacing and path field
2.6.0
- CLAUDE.md template system: store multiple presets, pick from dropdown in New Gem panel
- Edit mode detection: Gem Settings shows whether a CLAUDE.md exists with option to insert
- Editor panel polish: spacing, text centering, focus ring, opacity sync
2.5.1
- History grouped by date: entries organized under Today, Yesterday, and older dates
- Auto-save fix: overwrites a single active file per shard instead of creating duplicates
2.5.0
- Session history: terminal output saved automatically when shards close. Browse, view, or delete from the History button. Auto-saves every 5 minutes.
- Shard close buttons: small × on shard pills for quick closing
- Stale branch recovery: orphaned worktree branches auto-detected and reattached or cleaned up
- Crystal Rail syncs icon and color when switching directories
2.4.0
- Session history: terminal output saved on shard close and app quit
- Shard close buttons: × visible when 2+ shards exist
- Stale branch recovery: branches with commits reattached, empty ones cleaned up
2.3.0
- Free tier expansion: isolated shards, API keys, and MCP server configuration now available to all users
- Shard limit increased from 3 to 5 per gem on free tier
2.2.0
- Worktree merge-to-main: rebase + fast-forward flow from status bar or right-click menu
- Warns about concurrent schema/migration changes in sibling worktrees
- No more Keychain prompts: API keys and license stored in
~/.config/crystl/with secure permissions
2.1.0
- Metal GPU rendering: hardware-accelerated terminal with automatic CoreText fallback
- Icon picker: fixed scroll behavior, category tabs stay fixed above scrollable grid
- Git-branch icons for isolated shards
- Directory picker close button
- Notification settings with descriptions for each type
2.0.0
First public release of crystl.
- Gem-based project organization
- Parallel shards (sessions) per gem
- Split view
- Conversation history
- Crystal Rail sidebar
- Guild membership with license activation
- Sparkle auto-updates