Version 0.1.0-prerelease.1
Pre-release
Pre-release
Release Notes
Added
F-plans-memory(M3, read-only first slice): browse and view Claude's plans
(~/.claude/plans/*.md) and memory files — the global~/.claude/CLAUDE.md
and each project'sCLAUDE.md— from a "Plans & mémoire" section in the
sidebar. Clicking one loads it off-thread and shows it read-only in the main
pane (✕ returns to the terminal); the doc list refreshes on each scan so
project memories appear once their paths are known. A newdocsfile adapter
lists and reads. Editing — and the~/.claudewrite-scope change it needs —
is a deliberate follow-up.F-session-metadata(M3): a star / archive / custom-title overlay on the
read-only Claude sessions, persisted to~/.termherd/metadata.json(we never
write under~/.claude). The browser pins starred sessions to the top of
their group, hides archived ones behind an "Afficher les archivées" toggle,
and shows custom titles. Star (★/☆) and archive (⊟/⊞) are per-row sidebar
buttons. The overlay is pure incore—SessionMeta, applied in
visible_projects, behindToggleStar/ToggleArchive/RenameSession/
ShowArchivedToggledevents that emit aSaveMetadataeffect (default
entries are pruned, so a toggle-back leaves no noise). Renaming is inline: a
✎ button swaps the title for an edit field that commits on Enter (or ✓);
while it is open the field owns the keyboard, so terminal routing pauses.F-keyboard-shortcuts(M3): a configurable keymap (FR9). Every shortcut is
now aKeyChord -> Actionbinding incore::keymap(pure, testable):
human chords ("ctrl+shift+c", order/case-insensitive) parse to a chord,
platform-aware defaults bind copy/paste/close/search (⌘ on macOS, Ctrl
elsewhere) plusCtrl+Tab/Ctrl+Shift+Tabtab cycling, and thekeys
section ofsettings.jsonoverrides any action (one chord or a list).
Unknown actions and unparsable chords are logged and skipped. The shell
builds a chord from each key event and runs the bound action, so the
hard-coded clipboard chords are gone and keyboard tab switching, tab close
and search focus now work;split-*/focus-next/prevactions are bound
as those features land.F-settings(M3, thin): user settings (FR10) persisted to
~/.termherd/settings.json. A shell profile (program + args) is injected
into thePtyManagerso each session launches the chosen shell instead of
the platform default; a GUI theme (dark/light) dresses the iced chrome
(sidebar, tab strip, buttons) while the terminal grid keeps its own colours.
Every field defaults, so a missing or corrupt file still starts cleanly.
Window bounds keep their ownwindow.json(FR12); an in-app settings panel
is the full version later, so for now the file is edited by hand.F-builtin-terminal(M2): clipboard copy/paste shortcuts (FR4).Ctrl+V/
Ctrl+Shift+Vpaste the clipboard into the focused PTY (previously only
copy-on-select existed, so there was no way to paste at all); the chord
shadows the raw^Vcontrol byte, the Windows-terminal convention.
Ctrl+Shift+Ccopies the current selection — plainCtrl+Cstays the
interrupt signal, as in every terminal. On macOS the Cmd key drives copy
(Cmd+C) and paste (Cmd+V) directly, leaving Ctrl free for the interrupt.
Multi-line paste is handled
correctly: newlines normalise to carriage returns, and when the application
has enabled bracketed paste (DECSET 2004, which theptyScreennow
reports) the text is wrapped inESC[200~…ESC[201~so it lands as one
block instead of submitting line by line.F-session-tabs(M3): open sessions are now navigable tabs, not just the
last-launched terminal. A tab strip above the terminal switches between
sessions; each chip carries its activity dot (the FR8 tab badge, folded to
the most urgent status of the sessions it hosts) and a close button. Closing
a tab kills its session's PTY — the first UI-drivenEffect::Kill— and
drops the session from the live registry and its cached screen. The tab tree
edits are pure incore(Workspace::activate/close_tab,Tab::sessions,
App::tab_status) behindEvent::ActivateTab/CloseTab, exhaustively unit
tested; the shell only renders the strip and forwards clicks. Drag-reorder
(FR5) and keyboard tab-switching (F-keyboard-shortcuts) are not yet wired.F-builtin-terminal(M2): the embedded terminal is now a real terminal.
Theptyreader builds aScreensnapshot — the visible grid with per-cell
RGB (resolved from the xterm-256 palette), the cursor and a scrolled flag —
fromalacritty_terminal's renderable content. The shell draws it on an
icedcanvas(colour cells + cursor), routes raw keyboard to the focused
PTY (control combos, named keys, cursor sequences, layout text; gated by a
terminal/search focus model so the search box keeps its own typing),
propagates window resize to the PTY's cell geometry, and resumes a Claude
session withclaude --resume <id>when a session row is clicked. Verified
end-to-end on Windows: clicking a session resumed a live Claude run inside
TermHerd, its OSC activity drove the badge, and keystrokes reached it.F-builtin-terminal(M2, completed): wheel scrollback and drag-to-select
with copy-to-clipboard close out FR4. Theptyadapter now runs a reader
thread (blocking PTY reads) feeding a terminal thread that owns the grid
and applies bytes / resize / scroll commands, so the viewport reacts to the
wheel immediately instead of waiting on the next PTY output. Selection is
tracked in the canvas, highlighted, and copied on release.F-status-notifications(M2, completed for the current surfaces): the
ptyreader thread decodes each raw chunk withtermherd_claude::osc
before the bytes reachalacritty_terminal(which would consume the
sequences) and folds the markers into a per-session status, emitting
PtyEvent::Statuson change. Beyond busy/idle, an OSC 9 notification — a
permission prompt or an explicit "needs your attention" ping — now maps to
a distinctAttentionstatus; it is sticky against a bare idle prompt (the
user still has to act) and cleared only when work resumes. The shell feeds
it tocore(Event::StatusChanged) and surfaces it as a coloured badge on
the focused terminal and as a per-session dot in the sidebar (corenow
records which Claude session each terminal resumed, so a browsed row shows
its live activity). Tab badges arrive with tabs (M3); the bell is decoded
but deliberately not treated as an activity status.F-builtin-terminal(M2, in progress):termherd-ptyadapter — one
portable-ptyPTY +alacritty_terminalgrid per session, owned by its
own reader thread (actor-per-session, the structural fix for the
realSessionIdrace, Q6). APtyResponderreplies to cursor-position
queries (ESC[6n), without which ConPTY never starts the child on
Windows. The headless core gained the terminal lifecycle —
Event::LaunchSession/TerminalInput/TerminalResized/PtyExitedand
Effect::Spawn/Write/Resize/Killover a monotonicSessionId
registry — and the iced shell performs those effects against the
PtyHostport: clicking a project opens a terminal, its live screen
renders as monospace text with a line-input box. Verified end-to-end on
Windows ConPTY (spawn → reply → write → grid → kill) and visually in the
shell. Pending: raw key input, colours/cursor/selection, scrollback,
widget-driven resize.- Initial scaffold: Cargo workspace (
core/claude/app), pinned
toolchain (1.95.0), MIT license, README, deny config. - CI:
fmt,clippy -D warnings,cargo test,cargo-deny, markdownlint
required on PR (Q2). F-foundations(M0): workspace skeleton, dependency rule,tracinginit,
single-instance lock intermherd-app.F-app-shell(M0): iced 0.14 window shell (OQ1 settled on iced) —
placeholder view, window bounds persisted to~/.termherd/window.json
on close and restored on launch (FR12); close requests intercepted so
bounds always save. The menu is deferred to M3: iced has no native menu
API, and the menu will mirror keymap actions (F-keyboard-shortcuts),
so they land together.F-search(M1): in-memory search (FR3) — case-insensitive over titles,
summaries, slugs and indexed text, titles-only toggle; pure
filter_projectsincorebehindEvent::SearchChanged, search box +
checkbox in the sidebar.F-session-browser(M1, completed): debouncednotifywatch on
~/.claude/projects(FR2) — bursts of fs events coalesce into one
rescan; the sidebar live-updates while Claude CLI writes. Verified
live: create/delete in the projects tree triggers a ~200 ms rescan.F-session-browser(M1, first slice):termherd-scanadapter — walks
~/.claude/projectswith upstream's exact derivation order (direct
JSONL, then session subdirs andsubagents/), worktree collapse with
the fs existence check, underivable folders dropped like upstream but
logged;core::browser— pure grouping (one group per real path, FR1;
recency ordering) behindEvent::ScanCompleted; the shell scans off
the UI thread at startup (FR2, initial scan only) and renders the
sidebar. Livenotifyupdates and FTS search still to come in M1.F-packaging-ci(M0, unsigned): cargo-dist 0.32 release pipeline —
tag-triggered GitHub workflow building mac (ARM + x64), Linux
(x64 + ARM) and Windows artifacts with shell/PowerShell installers and
checksums. Windows artifact verified locally (10.6 MB binary vs the
Electron app's ~150 MB). Signing/notarization pending certificates
(OQ5).- First TDD targets:
termherd-core::workspace— pane tree + tabs with unit tests
(open / split / focus).termherd-claude::path—encode_project_path, byte-faithful port of
the JS reference, with unit tests.termherd-claude::derive— real-project-path recovery (extract_cwd
from JSONL, worktree collapse), ported fromderive-project-path.js;
unit + property tests.termherd-claude::digest— session digest (summary, title precedence
per the #46 contract, message counts, FTS text), ported from
read-session-file.js; deliberately skips corrupt lines instead of
dropping the whole session (Q5); unit + property tests.termherd-claude::osc— PTY status decoding (busy spinner / ✳ idle /
OSC 9 notifications / alt-screen / bell), ported from the inline
main.jsparsing; unit + property tests.- Codec validated against a real
~/.claude/projectstree: every derived
cwdre-encodes to its folder name; all sessions digested.
docs/background/— imported the four 2026-05-27 analysis docs that
produced the restart decision (assessment, feature sizing, the Electron
app's architecture and NFRs) plus an index README.
Install termherd-app 0.1.0-prerelease.1
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/bastien-gallay/termherd/releases/download/v0.1.0-prerelease.1/termherd-app-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/bastien-gallay/termherd/releases/download/v0.1.0-prerelease.1/termherd-app-installer.ps1 | iex"Download termherd-app 0.1.0-prerelease.1
| File | Platform | Checksum |
|---|---|---|
| termherd-app-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| termherd-app-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| termherd-app-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| termherd-app-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| termherd-app-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |