v0.5.1
Recommended install: brew install itsdezen/tap/tili —
Homebrew downloads via curl, which doesn't set macOS's
quarantine flag, so Gatekeeper never enters the picture.
The tarballs below are codesigned with tili's self-signed
certificate (hardened runtime) — see
CONTRIBUTING.md.
That's for a stable signing identity across releases (so
your Accessibility grant survives an upgrade), not for
passing Gatekeeper — a self-signed cert isn't notarized. If
you download tili.app directly from this page instead of
using Homebrew, Gatekeeper will still prompt on first launch:
right-click → Open, or xattr -d com.apple.quarantine tili.app.
Fixed
- Moving "the focused window" to another workspace could act on a stale,
previously-focused window instead of whatever the user actually had
focused — most reliably reproduced with a floating window (e.g. Note)
sharing a workspace with a tiled one (e.g. Ghostty). Root-caused to two
compounding gaps: (1)tili-daemon's event loop only applied a pending
new-window registration on the next 30ms maintenance tick, so a hotkey
fired right after opening a window could dispatch before that window was
even known about — now drained before dispatching a hotkey- or
socket-triggered command instead. (2) The system-wide focus check
(sync_focus_from_frontmost, run before every command) read
kAXFocusedWindowAttribute, an attribute macOS's system-wide
accessibility element never actually populates — confirmed on real
hardware it silently failed on every call, every time, regardless of
what was focused. Now readskAXFocusedUIElementAttribute(the one
attribute the system-wide element reliably supports) and resolves the
owning window from whatever control that returns. tili uninstallcould still delete the real config file when a
dotfiles tool symlinked the whole~/.config/tilidirectory, rather
than justtili.kdlitself — the file-level symlink case was already
handled, but a symlinked ancestor directory wasn't. Now walks every
ancestor of the config path and leaves it in place if any of them is a
symlink.brew upgrade tilididn't actually restart onto the new binary.
post_install's restart works by signaling the running process and
relying on the LaunchAgent'sKeepAliveto relaunch it — but the plist's
cached path was fully resolved to a specific, version-pinned Cellar path,
which never changes on its own, so every upgrade kept relaunching the
exact same old binary until a manualtili stop && tili start.tili startnow resolves that path through Homebrew'sopt/tilisymlink
instead, which Homebrew itself relinks to the current keg on every
upgrade. If you're upgrading from an affected version (v0.4.3 or
later), runtili stop && tili startonce after this upgrade to
regenerate the LaunchAgent plist with the corrected path — this fix only
changes what a futuretili startwrites, not an already-installed
plist.
Full changelog: CHANGELOG.md