Skip to content

Kotgent 0.6.0 — Junie, shell sessions, and a command palette

Choose a tag to compare

@github-actions github-actions released this 07 Aug 09:37
· 401 commits to main since this release

Junie is the third provider

junie joins claude and codex as a full agent: launched as a TUI inside tmux, reporting through
hooks into the local ingress, with the same events, approvals, resume and reconciliation as the others.
Three things it does differently are handled rather than papered over. Its hooks ride a per-launch
--config-location file, never ~/.junie/config.json, so kotgent's hooks fire only for the sessions it
starts. Its PermissionRequest hook exits 1 on purpose — an exit of 0 would auto-approve and 2
would auto-deny, and kotgent never answers an approval for you. And its session ids are not UUIDs
(session-260730-015553-1j1h), so discovery enumerates session directories by birth time instead of
waiting for the index row that only appears after the first task.

Shell sessions

A plain login shell is now a fourth agent kind, not a new session dimension: it reuses the one launch
path and all the generic tmux, terminal, control, archive and reconciliation machinery. Pick Shell in
the New-session dialog (or ⌘K t) and you get a tmux pane you can attach to from the browser, the
phone or kotgent attach.

Closing a pane is now observed rather than inferred later: a session-closed hook installed in the same
invocation that creates the session tells the daemon to re-derive that session's state from pane
liveness and the vendor probe.

Import an outside session

kotgent import — and Import mode in the Web UI's New-session dialog — brings a session you started
outside kotgent under management with zero tmux side effects. It writes a resumable row and leaves
the actual launch to the existing resume path, so there is no second launch codepath and a failed start
stays honest. The working directory is canonicalized through the filesystem before it is validated with
the same probe the reconciler re-runs on every daemon start, so an import that succeeds keeps working
across restarts. Without --cwd, the directory is discovered from the provider's own records.

Command palette and one dark theme

⌘K opens a searchable palette; a leader chord reaches the same commands by mnemonic. Rare actions moved
there out of the sidebar chrome, which is now just the notification toggle. The desktop sidebar collapses
and remembers it. The Web UI is dark-only, with a Kotlin-purple accent, pill session rows and floating
cards.

Sessions list

Sessions group into a nested folder tree by path. The list is now built from the /events socket alone —
one snapshot on connect, then per-row frames — and every session row carries a global monotonic rev, so
HTTP responses and WebSocket frames merge safely in any arrival order and the old periodic resync is
gone. Resuming a session that was marked Done un-archives it, instead of reviving the agent under a row
the sidebar still hid.

Terminal

A repaint is shipped as one frame. A TUI hides the cursor before repainting and shows it at the end, so a
read that turns a visible cursor off is now held until ?25h arrives and the whole repaint is broadcast
at once — that removes the ~3 cursor dropouts per second the previous per-read forwarding produced.
Full-screen apps that hide the cursor for their entire run are unaffected.

Phone

Swipes scroll the terminal. xterm's own touch scrolling is off while mouse tracking is on, which kotgent
needs for the desktop wheel, so a claimed one-finger vertical swipe is replayed as wheel events on
xterm's element — banked per gesture and emitted by a frame loop that coasts after the finger lifts.
Files can be uploaded into a session's working directory from the palette's f command, one at a time,
with the daemon accepting a single leaf filename and never overwriting an existing file. The iOS
standalone PWA's safe-area handling is fixed.

Assets

Static assets are invalidated by a content revision in the path (/_v/<rev>/) instead of a hand-bumped
?v= query. Because an ES module specifier resolves against the importing module's URL, one substitution
in index.html reaches the entire import graph — the old token versioned 3 files out of 34. A valid
revision means the bytes can never change, so those responses are immutable; everything else, including
index.html and sw.js, revalidates.

Full changelog: v0.5.0...v0.6.0

Upgrade

brew update
brew upgrade kotgent
kotgent install

Re-run kotgent install: the launchd plist stores a version-qualified Cellar path, so without it launchd
keeps starting the previous binary.