Changelog
# Changelog
All notable changes to Transit are documented in this file.
The format is based on Keep a Changelog,
and Transit adheres to Semantic Versioning.
How this file feeds the release pipeline:
- Versions map 1:1 to git tags (
vX.Y.Z) and to the per-version folders
published at <https://downloads.transitai.app>.
- When a
vX.Y.Ztag is pushed,release-prod.ymlruns
scripts/extract-changelog.mjs X.Y.Z to pull the matching ## [X.Y.Z]
section verbatim into the GitHub Release body and the download page's
release notes. A missing or empty section fails the release — so move
items out of [Unreleased] into a dated ## [X.Y.Z] section *before*
tagging. scripts/bump-version.mjs X.Y.Z is the companion that bumps the
version files in lockstep.
- HTML comments are stripped from every published copy (the extracted
section AND the raw CHANGELOG.md uploaded to the downloads bucket, via
scripts/lib/strip-html-comments.mjs) — so repo-internal notes like the
CLAUDE.md §18 cost-impact records may live here as `` blocks.
An unbalanced comment marker fails the release. Comments are internal, not
secret: this file is still in the repo, so credentials never belong here.
[Unreleased]
[6.5.6] - 2026-09-03
Added
- Linux packages for ARM64 (aarch64). Transit now publishes a
.deband an
.rpm for ARM64 alongside the existing x86_64 packages — four Linux
downloads per release. Both are built natively, with the same
distro support as before (.deb: Ubuntu 24.04+ / Debian 13+; .rpm:
Fedora / RHEL 10 with EPEL). The install script picks the right
architecture automatically, and the downloads page lists each one
explicitly. Linux still has no in-app auto-update, so updating means
re-running the install script or downloading the newer package.
[6.5.5] - 2026-09-03
Fixed
- **RSA key auth on modern IOS-XE 17.x (and similar) that only accepts SHA-1
signatures.** Follow-up to the v6.5.4 fix. Some devices negotiate a fully
modern key exchange yet still require the legacy SHA-1 ssh-rsa signature
for *user-key* authentication and never advertise which signatures they
accept. Because the key exchange is strong, the weak-crypto prompt never
appeared, so RSA key auth dead-ended. Transit now recognizes this case and
surfaces the same per-device weak-crypto prompt used for legacy key
exchange; approving it (optionally "Remember for this device") completes
the connection with the SHA-1 signature the device wants. As before, the
SHA-1 signature is never used without that explicit approval, and an
ed25519 key still avoids the prompt entirely.
[6.5.4] - 2026-09-03
Fixed
- RSA key authentication against legacy devices (old IOS-XE and friends).
Gear that predates RFC 8308 never announces which RSA signature flavors it
accepts, and Transit's best-effort guess (rsa-sha2-512) was a signature
such devices cannot verify — so key auth failed in Transit while the same
key worked from OpenSSH. With weak crypto allowed for the device (the same
opt-in this gear already requires for its SHA-1 key exchange), Transit now
signs with the legacy SHA-1 ssh-rsa, matching OpenSSH's assumption for a
silent server. Without the opt-in nothing is downgraded, and a rejected key
now explains the likely cause — and the opt-in remedy — instead of a
generic "server rejected the credential".
[6.5.3] - 2026-09-02
Added
- Settings → General → "Confirm before closing a connected session". On by
default, unchanged from before. Turn it off and a tab's ✕ (and a pane's
Disconnect) closes on the click, with no dialog. Customer request:
some people just want the ✕ to mean close.
Two prompts are kept either way, because they are not the same risk.
Close all tabs and quitting the app take down the whole workspace at
once. And a Files tab with transfers still in flight keeps its
confirm because that one warns about losing work rather than about
disconnecting — a preference about closing sessions should not quietly
start cancelling transfers.
Fixed
terminal length 0never took effect on Arista EOS. Transit sends
it at connect so long show output doesn't stall behind --More--,
and on EOS the command was sent, echoed into the scrollback — so it
looked like it had run — and then silently discarded by the device,
every session.
A live SSH shell channel is not a live CLI. EOS runs its CLI as a
separate process and discards anything typed before its prompt appears
rather than buffering it, so bytes sent the instant the shell came up
landed nowhere. Transit now waits for the device to actually look
ready — output gone quiet and a prompt-shaped tail — before sending
the paging init, bounded so a device with an unrecognizable prompt is
no worse off than before. Connect is not slowed: the wait happens in
the background.
Reported by a customer and reproduced in the lab. Not strictly
Arista-specific — any CLI slow to present a prompt could lose the init
the same way; EOS is simply slow enough to expose it every time.
- The AI agent couldn't use Arista's own pager bypass. EOS accepts
<command> | no-more to return one command's full output with no
--More--, and Transit's per-vendor command gate was denying it — the
pipe stage was simply never added to the Arista allowlist, and the gate
default-denies what it doesn't recognise. It is read-only by
construction (it suppresses the pager; it cannot write a file or escape
a mode, which is what separates it from tee / redirect / append,
which stay blocked), so the denial was an omission rather than a
judgement.
This matters for capture reliability, not convenience: the agent waits
for output to go quiet, and a --More-- prompt is silent while it
waits for a keypress, so a paginated command stalls to the timeout and
returns truncated output. | no-more cannot be lost to device state
the way a terminal setting can.
Added
- **Interface error counters are highlighted, and the highlight knows the
difference between zero and non-zero.** A non-zero count is red — the
thing you are actually hunting — and a zero count is green, an
affirmative all-clear. Both shapes vendors print are covered: the
count-before form (5 input errors, Cisco/Arista show interface) and
the count-after form (Framing errors: 3, Junos `show interfaces
extensive`), including a mix of both polarities on the same line.
This also closes a plain gap rather than just adding a keyword: the
plural never matched at all. The severity pattern's word boundary
could not hold between the r and the s, so error highlighted and
errors did not — and errors is the form every interface counter
uses, which made the most-read line in troubleshooting the one line
that never lit up. Requested by a customer.
Changed
- Refreshed frontend dependencies — 22 patch/minor bumps including Vite 8.2,
Vitest 4.1.11, ESLint 10.9, zod 4.5, lucide-react 1.35, react-hook-form
7.86, TanStack Query 5.102, and the testing-library set.
Two updates were deliberately held back: TypeScript 7
(@typescript-eslint/eslint-plugin still peer-caps TypeScript below 6.1,
so taking it breaks npm ci outright) and react-resizable-panels 4 (a
two-major jump on the library behind terminal pane tiling and the Files
dual-pane — it gets its own change with its own smoke test rather than
riding in a routine refresh).
- Refreshed Rust dependencies — 10 semver-compatible bumps: async-trait,
log, thiserror, serde_yaml_bw, base64, uuid, time, trybuild, rcgen, and
flate2.
Six updates in the same Dependabot group were not taken, because each
is semver-breaking (for a 0.x crate the minor is the breaking axis) and
none belongs in a routine refresh: russh 0.63, sha2 0.11,
portable-pty 0.9, age 0.12, fontdb 0.24, and
system-configuration 0.8. The group as Dependabot proposed it did not
compile at all — see the PR for the kem/ml-kem trait mismatch.
Neither refresh changes user-visible behaviour; the full frontend suite,
the Rust workspace suite, and the production build all pass on the new
versions.
Fixed
cargo denyfailed on every pull request afterchacha20 0.10.0was
yanked from crates.io. Bumped to 0.10.2 (a patch inside the same
compatibility range). No functional change — the crate arrives
transitively through the SSH stack and Transit never names it.
Internal
vite.config.tsusesimport.meta.dirnameinstead of__dirname. Vite
8.2 warns that __dirname is unsupported by the configLoader: 'native'
mode slated to become the default in a future major, so this is the
forward-compatible spelling.
[6.5.2] - 2026-08-31
Added
- The left sidebar is now resizable. Grab the rail's right edge and drag,
or focus the handle and use the arrow keys (Shift for a coarser step);
double-click or press Home to snap back to the default 280px. The width is
clamped to 180px–50% of the window and remembered across restarts.
The fixed 280px rail truncated device names for anyone with a deeply nested
inventory — each level of grouping indents the row 12px, and a host:port
column holds a floor on the right, so a device three groups down had barely
a hundred pixels of name to work with. Reading the tree meant hovering rows
for their tooltips.
One width is shared by all five rail views (SSH, Terminal, Files, APIs,
PCaps) rather than one per view — the rail is a single column, and per-view
widths make the layout jump every time you switch surfaces. (Consolidating
on one default makes the PCaps rail 8px narrower than before at its default
width; every other view is unchanged until you drag.)
Changed
- The chat panel's drag-to-resize now runs on the same shared handle as the
sidebar's, so both edges behave identically. The chat panel also picks up
the keyboard resize, the double-click reset, and the focus ring it did not
have before; its clamp (320px–70%) is unchanged.
[6.5.1] - 2026-08-30
Fixed
- Packet capture never worked on Linux. The capture supervisor read the
heartbeat with stat -f %m — BSD syntax. On GNU coreutils -f means
--file-system, so the read returned a multi-line filesystem report
instead of a timestamp and $((NOW - BEAT)) killed the supervising shell
with "Illegal number" on its first loop iteration, before it could reach
its own cleanup. Captures produced zero packets and reported only the
generic "nothing matched the filter, no traffic, or it failed to start".
Not a permissions problem: the unprivileged→pkexec elevation ladder was
working correctly the whole time. macOS and Windows were unaffected.
- Linux packet capture wrote to a folder the OS forbids. Captures
defaulted to ~/.local/share/Transit/captures, and Debian/Ubuntu confine
tcpdump with an AppArmor profile carrying audit deny @{HOME}/.*/** mrwkl
— an explicit deny, which in AppArmor beats every allow rule — so no file
could be created anywhere beneath a hidden folder in the home directory.
AppArmor mediates above uid, so this failed identically as root: the audit
record reads operation="mknod" denied_mask="c" fsuid=0. **The Linux
default is now ~/Transit/captures**, a visible folder the same profile
permits. macOS and Windows keep the locations they already used, and
nothing is migrated because a live capture could never have written to the
old path.
- A capture that could not create its file asked for a password anyway.
An unwritable output folder and an unusable interface both report
"Permission denied", and Transit treated both as "needs elevation" — so it
raised a pkexec prompt whose elevated retry then failed exactly the same
way. The user authenticated and still got an empty capture. Output-path
denials are now told apart from interface denials and reported with the
folder that refused, instead of being escalated to a prompt that cannot
help.
- Rotating captures produced no file on Debian/Ubuntu. Their tcpdump is
built --with-user=tcpdump, so a capture started as root drops to that
unprivileged user before writing; every -C rotation file after the first
is then created inside a directory owned by the invoking user and fails
with "Permission denied". Linux captures now pass -Z <user> so the files
land owned by the person who asked for them. macOS is unchanged — its
tcpdump does not drop privileges.
- An elevated capture that fails immediately now says why. The
privileged branch returned its child without the fast-fail and stderr
check the unprivileged attempt already had, so a declined or unavailable
authentication surfaced as a mystery empty capture.
[6.5.0] - 2026-08-28
Added
- Jump hosts (SSH ProxyJump) — a device can now connect *through*
another inventory device (jump_via, SecureCRT's "Firewall" concept):
Transit logs into the jump host with its own saved profile, opens an
end-to-end-encrypted tunnel, and verifies the target's host key through
it — the jump box never sees the target's password or traffic, unlike
hand-typed nested ssh. Chains up to 4 hops; per-hop trust prompts;
works for terminals and the Files (SFTP) pane; assignable in bulk
("Edit N devices → Jump host"); the AI agent's per-vendor command gate
adjudicates the *target's* policy through the tunnel. Imports now carry
ssh_config ProxyJump / SecureCRT Firewall Name into the field when
they match an imported or existing device.
- SSH agent forwarding — per-device, off by default: shell into a
bastion you trust and let git/ssh there authenticate with your local
agent (1Password's per-use prompt works as usual). Clearly warned in the
device dialog; deliberately excluded from bulk edit and settings
bundles; live sessions keep their connect-time setting.
Security
- Inbound
auth-agent@openssh.comchannels are now **explicitly
rejected** unless the device opted into agent forwarding (the bundled
SSH library's default would have accepted them); threat-model entries
T52 (jump hosts) and T53 (agent forwarding) added.
[6.4.0] - 2026-08-26
Added
- Linux
.rpmpackage for Fedora and RHEL/AlmaLinux/Rocky 10, alongside the
existing .deb. Built on almalinux:10 with EPEL, whose older glibc means one
package covers EL10 and every live Fedora. On EL10, enable EPEL first — it is
the only Enterprise Linux source of webkit2gtk4.1; Fedora has it in base.
EL9/RHEL 9 is not supported (no webkit2gtk4.1 in EL9 or EPEL 9, and
libsoup2/libsoup3 cannot coexist in one process). Like the .deb, the .rpm
has no in-app auto-update — updates are download-and-reinstall.
- "Own tab" button on a split pane, lifting it back out into its own
top-level tab. Splitting was previously one-way: closing the pane was the only
way out.
- Focus ring on the active pane of a split tab, so it is visible which
terminal the button bar and Clear Terminal will act on.
Fixed
- Button-bar macros went to the wrong pane in a split tab. Macros always
fired into the tab's primary (left) pane regardless of which pane held the
cursor, and the post-send focus hand-back then dragged the cursor there too.
Both now follow the focused pane. Reported by a customer on Windows.
- Cmd/Ctrl+Shift+K cleared the wrong pane in a split tab, wiping the primary
instead of the focused pane. Same root cause as the button-bar bug.
- Session info panel described the primary pane rather than the focused one
in a split tab.
[6.3.1] - 2026-08-24
Changed
- Adjusted token rates to reflect promotional pricing from upstream cloud
providers.
Fixed
- Long investigations now run their full length before pausing. The
internal threshold that decides when the AI stops to ask whether to keep
going was miscalibrated for some models, so chats could stop short of
where they should have. This threshold is internal and is never shown in
the app.
[6.3.0] - 2026-08-21
Added
- Keep chat history (opt-in). Settings → Agent Chat → "Keep chat
history": your open AI chats come back after a restart — transcript,
model, and tab name included. Off by default; when on, each chat is
saved to a folder you choose after each turn (turns you stop midway
included), passes Transit's redaction filter again on the way to
disk, and closing a
chat deletes its file. Restored chats always come back with fresh
approval state: command auto-approvals, device scopes, and API
auto-approve never persist.
- Save AI code blocks to file (opt-in). Settings → Agent Chat →
"Save code blocks to file": every code block the AI writes gets a
Save button. Saving always opens the system save dialog — you pick
the destination each time (starting at a folder you choose), and the
AI itself has no way to write files: the button click is the entire
authority, and the app never marks a saved file executable.
- Bulk edit devices. Select several connections (Shift-click a range,
Cmd/Ctrl-click to toggle) → right-click → Edit N devices…, or
right-click a group folder → Edit all in group — one dialog changes
vendor, auth profile, accent color, bold accent, syntax highlighting,
quick copy/paste, and terminal font across the whole selection. Every
row defaults to Leave as is, so only what you pick changes, and the
batch is all-or-nothing: if any device fails, nothing is written.
- Any accent color. The per-device accent picker gains a Custom
swatch backed by the OS color picker — any #rrggbb, beside the seven
theme-aware presets (a custom color is the same in light and dark; the
presets keep adapting). Button-bar buttons accept custom colors too.
- Enter sends in the AI chat. Plain Enter now sends and Shift+Enter
inserts a new line (⌘/Ctrl+Enter still sends, as before). The new
Settings → Agent Chat tab hosts the toggle for anyone who prefers
the old ⌘/Ctrl+Enter-only mode for hand-typed multi-line prompts.
Fixed
- **Linux: the SSH-agent setup hint no longer suggests starting a fourth
agent.** On Linux desktops, "start one with eval $(ssh-agent -s)" hid
the real problem — GNOME Keyring, systemd's ssh-agent socket, and
gpg-agent all compete for SSH_AUTH_SOCK. The hint now points at the
durable fix (mask the competing user services and pin the agent socket
in environment.d, then re-login), documented in
docs/security/secrets.md under "Linux: agent contention".
[6.2.1] - 2026-08-20
Fixed
- macOS: opening the Terminal tab no longer asks to install Python 3.
Shell discovery version-probes every candidate it finds on PATH, and on
a Mac without the Xcode Command Line Tools, /usr/bin/python3 is Apple's
installer shim — merely running --version on it pops the OS "install
the command line developer tools" dialog. Discovery now asks
xcode-select -p first (which never triggers the dialog) and skips the
shim entirely when the tools aren't installed; a real Python elsewhere on
PATH still appears in the launcher.
[6.2.0] - 2026-08-19
Added
- NetBox as a first-class API vendor. A NetBox preset in the New API
controller dialog (auth pre-filled for classic Authorization: Token <key>
tokens; NetBox 4.4+ nbt_… v2 tokens use Bearer — the dialog hint covers
both) and a bundled, curated investigation collection: ~31 GETs across
Circuits / Devices / Sites / IPAM, generated from NetBox's own OpenAPI
schema by scripts/gen-netbox-collection.mjs, which validates every path
and filter param against the spec. Includes the circuit-outage walk
(circuit → terminations → devices at the site → interfaces → IPs) and the
everyday lookups ("who has this IP?", "prefixes containing", devices by
site/role/tag/search). The AI agent reaches NetBox through the same
structurally GET-only, host-pinned propose_api_call as every API session.
Setup + worked example: docs/integrations/netbox.md.
- API-key auth value prefix. The
api_keyauth scheme can now prepend
non-secret text to the key in the header value —
auth = { scheme = "api_key", header = "Authorization", value_prefix = "Token " }
is the NetBox classic-token shape, and the same field serves any
Authorization: <Word> <key> API. Existing sessions are untouched: an
empty prefix sends the bare key, byte-identical to before, and the field
is omitted from the TOML when empty.
- Sync inventory from NetBox. The import pane gains a live source
beside SecureCRT/MobaXterm/CSV: pick your NetBox API session, and Transit
pages the device list (read-only, through the same host-confined client)
and diffs it against your inventory on a stable per-device NetBox id —
New devices import through the standard review grid (per-row
vendor/group/auth, bulk edit, collision handling; site → group,
platform → vendor with BYOP fall-through, tags + role carried);
Changed devices offer per-field accept/skip for host/vendor/group
drift; Stale rows (gone from NetBox) default to Keep, with explicit
per-row Unlink or Delete — deletes are re-confirmed by name before the
one atomic commit. Nothing is ever written to NetBox, nothing syncs on a
schedule, and the AI agent has no path to any of it (threat-model T49).
Fixed
- The public downloads page no longer shows changelog authors' internal
notes: HTML comments in this file are now stripped from every published
copy of the release notes (the v6.1.1 notes on the downloads page rendered
one as visible text; the live copies were scrubbed).
- Sidebar tag chips no longer render inline at all — a device with several
tags (as NetBox-synced devices are) squeezed its own name down to a
sliver. The name and host get the full row; the tags remain in the row's
hover tooltip and in tag filtering.
- Native dropdowns (the API controller dialog's vendor/surface/auth/backend
selects, the PCaps interface picker, the NetBox sync auth picker) now set
an explicit text color — WebKitGTK doesn't cascade the app's color into
form controls, which rendered them white-on-white in light theme and
near-invisible in dark.
[6.1.1] - 2026-08-15
Added
- The assistant's working surface got six upgrades (the harness batch,
driven by 2026-08-14 live testing across cloud and local models):
the session roster shows how much scrollback each session holds
(scrollback: empty means run a command first); command results say WHY
their capture ended — capture="silence" warns that a quiet device may
still be producing output (no more invented ping results), with timeout
and session-closed variants; refusals teach the next move (policy
denials open with "Transit's policy gate denied this command — the device
never received it" and point at the vendor's policy section, so a refusal
is never mistaken for device behavior; context-overflow errors say how to
recover); read_scrollback
gains a match filter (literal substring + context lines + an honest
total_matched, including 0 = appears nowhere) so investigations stop
re-reading whole rings; pruned-history breadcrumbs name the session,
device, and command they replaced; and every built-in vendor policy now
carries a phrasebook — known-good command forms in that vendor's own
syntax, rendered into the assistant's instructions and build-tested so
every entry passes that vendor's policy gate.
Changed
- The AI names sessions
s1,s2, … instead of long internal ids. The
session listing, the assistant's prompt, and every command/read result now
use a short, stable per-chat alias; results are also stamped with the
device they actually came from (<session id="s1" device="R4">), and the
assistant's session roster shows how many commands have executed on each
session this chat — so "which devices have I actually checked" is a fact
in front of the model, not a memory it has to keep. Long internal ids are
still accepted if a model (or an old transcript) sends one. Driven by
2026-08-14 live testing: local models mangle 36-character session ids
under multi-session load.
- New config key:
[local_models] turn_token_ceiling(default 4096,
env TRANSIT_TURN_TOKEN_CEILING) caps how many tokens the assistant may
generate in a single response, ending runaway responses that previously
streamed until a manual Stop. Applies to cloud and local models; local
models keep their existing half-context-window clamp (the smaller wins).
[6.1.0] - 2026-08-13
Added
- **Two terminal fonts now ship with Transit — JetBrains Mono and Cascadia
Mono.** Pick either in Settings → General; no install required, and they
look identical on every machine. On macOS this is the only way to use a
font Apple didn't ship: the system web engine refuses fonts you install
yourself, which is why a font you can see in other apps never appeared in
Transit's picker.
- Export and import your settings (Settings → General). Writes your
preferences and saved connections to one file you can carry to another
machine. Passwords are never included — they stay in your OS keychain —
and neither are host-key fingerprints, so the new machine still verifies
each device itself the first time it connects.
- Ubiquiti UniFi is now a built-in vendor with a shipped read-only
command policy, instead of a sample you had to install yourself. Because
a UniFi device gives you a Linux shell rather than a fixed vendor CLI,
every AI-proposed command needs your click — the "always allow" shortcut
is deliberately unavailable for UniFi devices.
- Copy and paste keyboard shortcuts on Windows and Linux —
Ctrl+Shift+C and Ctrl+Shift+V. Plain Ctrl+C still interrupts the running
command, as it always has, even when text is selected.
- Sort tabs alphabetically — right-click the tab strip, or use
Window → Sort Tabs Alphabetically. The Window menu also gains
Jump to Session…, which opens the command palette (Cmd/Ctrl+K) where
every open session is listed by name.
- Button-bar buttons can now target the AI instead of the terminal.
Choose "AI prompt" when creating a button and its text lands in the chat
box for you to review and send — a saved-prompt palette next to your
saved-command one.
- **Interactive sign-in — type your password (or one-time code) when you
connect. A new Ask me each time (interactive / MFA)** option on an auth
profile stores nothing: Transit relays the device's own login prompts, you
answer them, and what you typed is used for that one connection and then
discarded. No keychain entry, no file, nothing to leak from a stolen laptop.
This is also the first Transit release that can sign in to gear behind
multi-factor authentication — TOTP, RSA and Duo codes, and PAM /
CyberArk account-selection menus. Those challenges change every time, so a
saved password could never answer them; until now those devices could not
be reached at all.
The prompt shows exactly which user@host:port is asking and quotes the
device's own wording separately from Transit's, so a device cannot dress
its prompt up as one of ours. Fields mask or show according to what the
device asks for, so a menu choice stays readable and a password never does.
Devices set to interactive sign-in are skipped by Launch all — each one
needs you at the keyboard — and are reported in the launch summary instead
of stacking up dialogs.
Changed
- The Developers tab in Settings finally has an icon like every other
tab.
Removed
- The amber "remote opened a full-screen interface" banner. It existed
to warn that keystrokes could act on a TUI the terminal had failed to
paint — a rendering problem that no longer happens. What was left was a
banner that appeared every time you opened nano.
- The Telemetry placeholder in Settings. Transit collects no telemetry,
so a card promising a future opt-in toggle for it only raised the
question it was meant to answer.
[6.0.2] - 2026-08-12
Changed
- The assistant's instructions now make multi-session scope explicit.
Every open session is a valid target, and an ask that spans sessions ("is
BGP healthy on these sessions?") means investigating each relevant one
before concluding. Cloud models already behaved this way — verified
unchanged — so this aligns the written contract with the expected
behaviour, which matters most for local (BYOM) models that tended to stop
at a single session. One-time note: this refreshes the assistant's cached
prompt once per user on first use after updating.
[6.0.1] - 2026-08-10
Fixed
- The assistant is now properly introduced to packet captures. v6.0.0
shipped the sixth tool (query_capture) but the assistant's instructions
still said it had exactly five tools, never described what query_capture
does, and never listed the captures you had open — so models sometimes
ignored an open capture or fumbled the first query. The instructions now
describe all six tools, and any open capture is named in the assistant's
view of your workspace (with [pcap] agent_access = false still removing
it entirely).
- The assistant is told each session's transport. Open sessions now
carry a kind (ssh / console / api) in the assistant's session
roster and in list_open_sessions, so it can reliably pick
propose_command for SSH/console sessions and the GET-only
propose_api_call for API/controller sessions — previously it had to
guess from the vendor, and a UniFi gateway reachable both ways made that
a coin flip.
- Executed command output is now framed as untrusted device bytes. The
output of an approved propose_command reaches the model wrapped in the
same <session id> tags as scrollback reads, closing a defense-in-depth
gap the 2026-08 prompt-contract review found (the policy gate + approval
modal were, and remain, the primary control). Capture answers were
already framed; the assistant's injection guard now explains both
framings.
[6.0.0] - 2026-08-08
Added
- Diagnostics (Settings → Developers). Turn on a log file, choose where it
goes, and reproduce a problem — then send us the file. Useful when something
fails on a machine we cannot get to, which is most of them. Off unless you
turn it on, keeps a week of daily files so it cannot fill a disk, and the tab
states plainly what is never written to it: no passwords, keys or tokens, no
host keys, no terminal output or command text, no packet contents, and
nothing exchanged with an AI model. It records that an operation happened and
whether it failed — not the data it carried.
- Packet capture and analysis (PCaps surface). A fifth left-rail tab —
PCaps — captures traffic from a network interface on your machine and
opens any .pcap, .pcapng or .pcap.gz file for analysis, as a tab
beside your SSH, console, API, local-shell and file-transfer sessions. Pick
an interface, optionally set a capture filter, and press Start; or open a
capture someone sent you. While it records, the sidebar shows how much has
been written and for how long — and says so plainly when a capture has been
running a while and written nothing, which is what a filter matching no
traffic looks like.
The explorer gives you three resizable panes — packet list, field tree, and
bytes — with a view filter in Transit's own syntax
(tcp.port == 443 and ip.src == 10.0.0.0/24 and dns.rcode != 0) that
validates as you type. Alongside them, an analysis drawer with
Findings, an overview digest, conversations, and a protocol breakdown.
Findings are the part worth knowing about. Transit computes them from
the capture rather than inferring them: MTU black holes, retransmission
rates per conversation, zero-window stalls (with how long the sender was
stalled), connections that were *refused* as distinct from ones that got no
answer at all, duplicate IP addresses claimed by two MACs, DNS failure
rates and unanswered queries, fatal TLS alerts, HTTP server errors,
cleartext credentials crossing the wire, and routing loops. Each one comes
with a one-click filter that shows you the evidence.
And the assistant can read the capture. Ask it why a transfer is slow,
what broke a TLS handshake, or which host is retransmitting, and it will
work through the same analysis you can see. It reads dissected fields and
computed summaries — never packet payload, which is not something it can
ask for. A single config flag ([pcap] agent_access = false) keeps the
explorer and turns off the assistant's view of it, for anyone who wants
packet analysis without the AI reading their traffic.
Transit ships no capture driver: it drives the capture tool your operating
system already has (tcpdump on macOS and Linux, pktmon on Windows). If
your machine already permits packet capture — as it does if you have
Wireshark installed — you will not be asked for a password at all.
Captures are bounded by size, file count and duration, so one you forget
about cannot fill your disk, and a Headers only option records enough
for flow and protocol analysis while capturing no payload whatsoever.
The capture folder is shown in the sidebar and opens in your file manager
with one click, and Settings → General → Capture folder moves it
somewhere with more room.
Set [pcap] enabled = false in config.toml to remove the surface
entirely.
[5.0.0] - 2026-08-04
Added
- File transfer (Files surface). A fourth left-rail tab — Files — opens a
SecureFX-style dual-pane file browser against the devices already in your
inventory: your machine on the left, the device on the right, as a tab beside
your SSH, console, API and local-shell sessions. It rides the inventory you
already have — same groups, tags and per-host colors in the sidebar, same auth
profiles, same host-key trust prompt and weak-crypto opt-in — so opening file
transfer to a device you can already reach is one click ("Open file
transfer"), including "Launch all" across a multi-selection or a folder.
Browse either side with sortable columns, a hidden-files toggle, an editable
path bar that always shows the path the server actually resolved, multi-select
(click / Cmd-click / Shift-range), and directories of ten thousand entries
that still scroll smoothly. Create folders, rename, refresh, and delete —
deletes are permanent and a folder delete says exactly what it will take with
it.
Transfers go both ways, with a live queue at the bottom of the pane:
per-file progress, transfer speed, time remaining, which file a recursive copy
is on, and Cancel on anything still queued or running. Four ways to start one
— double-click a file to send it to the other pane, the toolbar arrow (or
right-click) for a whole selection, drag rows between the panes, or **drag
files in from Finder / Explorer** to upload them. Folders copy recursively,
modification times are preserved, a cancelled download cleans up its partial
file, and anything deliberately skipped is reported with a reason instead of
quietly disappearing. When something already exists at the destination Transit
asks once for the whole batch — Overwrite all / Skip existing / Cancel —
never file by file. Closing a tab or quitting mid-transfer asks first; an idle
browse session never nags. If the link drops, the tab keeps both folders and
offers Reconnect in place.
It is a free, human-only surface: the AI agent is structurally blind to
it — there is no file tool (the tool surface stays at five), the Files session
state is wired into none of the agent's session seams, and the new
transit_files crate is banned outside the app binary at the dependency-graph
level, so no future refactor can quietly hand the agent a filesystem.
Filenames the device sends are validated before they can influence a path on
your disk, and a recursive download never follows a symlinked directory on the
device. A [files] enabled = false config switch removes the whole surface for
locked-down / MDM deployments, which doubles as a DLP answer. SFTP today (on
Junos, enable set system services ssh sftp-server if it isn't already); SCP
for SFTP-less gear is designed as a fast-follow on the same queue.
New transit_files crate (russh-sftp); threat-model T43.
[4.4.0] - 2026-08-04
Added
- Local OS terminal (Terminal surface). A third left-rail tab — Terminal
— next to SSH and APIs, opening a real local shell (zsh / bash / fish /
PowerShell / cmd / WSL / python·node REPLs) in a PTY, as a tab alongside your
SSH and console sessions. The launcher **discovers the shells installed on your
machine and shows their versions ("look under the hood"); click one (or +**
for your default) to open it. Full terminal experience — keystrokes, real
window resize, clear-terminal, multiple tabs, session logging/export, and a
close-confirm on a live shell. When a shell exits, **press Enter to start a new
one in place** (scrollback preserved).
It is a free, human-only surface — the AI agent is structurally blind
to local shells (it can never see or run commands in them). A
[terminal] enabled = false config switch removes it entirely for
locked-down / MDM deployments. New transit_localpty crate (portable-pty);
threat-model T42.
- Terminal pane tiling. Split any terminal tab into a resizable grid —
panes side by side or stacked, nested to any depth (like Windows Terminal /
tmux) — across SSH, serial console, and local-shell sessions. Built on a
PaneNode layout tree (react-resizable-panels); closing a pane never resets
an untouched pane's scrollback.
- Drag-to-split. Drag a session tab onto another tab's pane and drop it near
an edge — left/right tiles beside, top/bottom tiles below. The edge
drop-zones highlight as you drag, and the dragged session (SSH or local shell)
moves into that tab's grid. Any pane is reachable, so you can fill a full grid
from separate tabs.
Changed
- Internal:
scripts/bump-version.mjsnow updates both lockfiles
(package-lock.json's root + packages[""], and src-tauri/Cargo.lock's
workspace crates) alongside the three declared version files, so a release
bump can no longer leave a stale lock for CI to catch later. No user-facing
change.
[4.3.1] - 2026-08-03
Security
- SSH transport updated to russh 0.62.5 (from 0.62.4), which carries
GHSA-m65r-rprj-r5rg. Transit was not exposed to that advisory — it
affects russh's *server* side (a server accepting channel callbacks for a
channel id it never opened) and Transit is only ever an SSH client, so no
Transit release could reach the vulnerable path. Updated anyway, because
shipping a dependency with a published advisory isn't worth the explanation.
The release also adds backpressure to the channel write path, which *is* the
path Transit uses to send your keystrokes.
Fixed
- A missing
:8443now says so. Omitting the port from a self-hosted
controller host meant Transit tried 443 and failed with a bare `HTTP
transport error`, which reads like a broken controller. A refused connection
on the implicit 443 now answers the actual question — *"nothing is listening
on unifi.example.com:443 — did you mean unifi.example.com:8443?"* — and a
silently dropped one names the other likely cause (firewall / cloud security
group / VPN, and that Transit connects directly and ignores any HTTP proxy).
An explicitly typed port is never second-guessed, and a self-signed
certificate still routes to the trust-the-fingerprint prompt rather than this
hint.
- "Local controller" made a supported setup look unsupported. The UniFi
Network API surface is now "Self-hosted controller" in the controller
dialog (and "Self-hosted" in the APIs sidebar). The three UniFi surfaces
differ by whether traffic is relayed through api.ui.com, not by whether the
controller is on your LAN — so a Network Application running on a cloud VM
(Azure, AWS) always belonged here, but the old label and its two LAN example
addresses read as on-link-only. The host field now says so outright and names
the port that trips people up (:8443 for a self-hosted Network Application,
443 for UniFi OS consoles). No change to the stored network_local kind —
existing controllers are untouched.
[4.3.0] - 2026-08-01
Added
- Seven more vendors ship with curated collections. Add a controller for
Cisco Meraki, Juniper Apstra, HPE Aruba Central, **Cisco ACI
(APIC), Cisco Catalyst SD-WAN (vManage), FortiManager**, or
FortiAnalyzer and Transit drops in a curated, investigation-focused
request collection — 447 endpoints across the seven, derived from each
vendor's official Postman export and named for the calls a network engineer
actually makes (device + uplink status, clients, health, interfaces, events,
rogue APs, fabric anomalies, control connections…). Pick the vendor and its
base URL + auth scheme are pre-filled; where a key is used it's stored by
reference in your OS keyring and injected at send time, exactly like UniFi —
the host stays pinned to the controller.
- Meraki uses a Dashboard API key (Bearer), so the investigation-only
AI agent can drive it too — GET-only and host-pinned, as always.
- Apstra / Aruba / ACI / SD-WAN authenticate with a login flow: pick
Login credentials for the auth scheme and store the username +
password once, then run "Log in first" — Transit fills the credentials
into the login request at send time and captures the returned session
token into a variable automatically, and the rest of the collection
carries it for you. Your password is read from the OS keyring (or
1Password / an env var) inside the app's backend and is never handed to
the UI, so it can't be read out of the window or left on disk. These are
human-first; the agent can ride a still-valid session when a static token
is configured.
- Every collection starts with the listings you need. Each vendor ships
the "what do I have?" calls that yield the ids everything else asks for —
Meraki's organizations / networks / devices / switch stacks, Aruba's
groups + guest portals, Apstra's config templates, SD-WAN's vSmart
policies — so you're never stuck with a request that needs an id you have
no way to look up.
- FortiManager / FortiAnalyzer are JSON-RPC (a single
POST /jsonrpc
endpoint), bundled for your use — the GET-only agent structurally
can't call them.
The collections are a human convenience: the agent stays GET-only and
host-pinned regardless of collection content, and you can edit, extend, or
import your own alongside them.
Security
- **Credentials typed into the request Variables bar are masked and never
written to disk.** Variables named like a credential (password,
client_secret, …) are hidden behind a reveal toggle, held in memory for
the session only, and carry the same "session" badge as a captured login
token. Any such value a previous build had persisted is purged the next time
Transit starts (rewritten out of local storage, not just ignored).
- A credential is refused in a URL path.
{{password}}in a request path
is an error rather than a substitution, for every controller regardless of
how it authenticates — a credential in a URL would be recorded verbatim into
the session history the AI agent can read, and into the controller's own
access log.
Fixed
- Every Meraki request failed before it was sent. The bundled Meraki
collection's paths were written absolute (/organizations/…) while the
Meraki base URL carries an /api/v1 prefix; an absolute path replaces the
base path, so the host-pinning check refused all 167 requests — for the
Postman client as well as the agent. Paths are now relative, matching the
UniFi local collections, and a test now resolves every path in every bundled
collection against its controller's base so this can't recur.
- The Apstra login request could not be filled in. Its body shipped with
literal <string> placeholders instead of variables, so it posted the text
<string> and failed to authenticate.
- **The response right-click "Set as variable" menu offered the wrong
variables.** It listed a fixed UniFi set on every controller, so Meraki's
{{organizationId}} — the id nothing works without — wasn't there at all.
The menu is now built from the open controller's own collection, and no
longer requires a variable to already have a value before it can be set from
a response.
- The AI agent can now investigate a login-flow controller. Its requests
went out with no session cookie, so every agent call against ACI, SD-WAN,
Apstra or Aruba came back 401/403 while the same call worked in the Postman
client. The agent now rides the session you established — it still
cannot log in itself (that's a POST, and the agent is GET-only), so if the
controller's token expires, re-run "Log in first" and it picks straight back
up — and because APIC's token refresh is itself a GET, the agent can keep
its own session alive. Meraki was never affected.
- Login requests across all seven vendors use the same
{{username}}/
{{password}} variables (they previously differed per vendor), so the
credential handling above applies uniformly.
[4.2.0] - 2026-07-31
Added
- Per-device appearance — font + a bolder color. The Edit-device dialog is
now organized into a settings-style left-nav (Connection / Organization /
Appearance / Terminal), and Appearance gains a per-device terminal font
(family + size, overriding the global font for that device's sessions only)
and a Bold accent toggle that renders the device's color as a louder
background tint on the session tab — not just the thin edge — so a prod box is
unmistakable at a glance. All optional and stored per-device in your inventory
(they travel with transit.toml). (Requested by Jeff Kish.)
- Your own API collections + Postman import. Every controller can now hold
collections of saved requests you build yourself — expand a controller in the
APIs sidebar to New collection, Save the request in the builder into
one (name it, pick or create the collection), and click a saved request to
reload it. Import Postman brings in an existing Postman v2.1 collection
(folders and all); auth headers are stripped on the way in and a saved
request never stores the API key (it's injected for you at send time).
Collections persist locally, per controller. (Part of v4.0.0 UniFi API
support.)
- The investigation-only agent can now **investigate API (controller)
sessions**. Open a controller and the agent immediately sees the session —
it reads the request/response history (redacted) via list_open_sessions /
read_scrollback, and can propose read-only GET requests without you
having to send anything first. Each GET passes a GET-only, host-pinned gate
and then an approval modal you click — or you can **opt into auto-approving
GETs** for a chat (the gate still runs on every one). It can never send a write
(POST/PUT/DELETE), reach any other host, or see the API key; its GET and
the response land in the controller's history for you to see. (Part of
v4.0.0 UniFi API support.)
- Point the API client at any REST controller, not just UniFi. Add a
controller with vendor Generic and a base URL, and Transit's Postman-style
tab + investigation agent work against any JSON/REST API — choose the auth
scheme (API key with a custom header name, Bearer token, HTTP Basic, or none).
The credential is stored by reference and injected server-side exactly as for
UniFi, and the host stays pinned to your base URL. http:// is allowed with a
warning (handy for local/dev gear) — prefer https over a network. The agent
is still GET-only and gated on generic controllers, with per-request approval
every time (no always-allow shortcut for a custom vendor).
- Session history in the controller tab. A Session history toggle in the
API pane shows the full request/response log the agent reads — your sends plus
the agent's approved GETs — with a Copy button, so you can see exactly what an
investigation saw.
- Response headers view. The API response panel gains a Body | Headers
toggle; Headers lists the response's header set (name/value) and Copy copies
whichever view you're looking at. (Headers are a human-only view — they are
never sent to the AI agent.)
- API controllers get SSH-parity settings: a tabbed dialog + color banners.
Adding or editing a controller is now a left-nav dialog (Connection /
Authentication / Organization / Appearance), and an accent color tints the
controller's session tab — so a client's production controller is unmistakable,
exactly like an SSH device.
- Reorder session tabs by dragging. Drag a terminal/console/API tab along
the strip to reorder it; a plain click still just switches tabs. Split panes
keep their pairing.
- Button-bar buttons can be given a color. The Map Button dialog gains a
color swatch (the same palette as per-host colors), and a colored button
renders with a subtle theme-aware background shade — group a "VOIP" set from
a "Routers" set at a glance, within a single bar. (Requested by Jeff Kish.)
Changed
- UniFi request-path ids are now settable variables, not inline placeholders.
Every id in a bundled request path — siteId, deviceId, and the rest, not
just consoleId — is now a {{variable}} you set once in the pane's Variables
bar and reuse across requests (right-click a value in a response → **Set
selection as variable** to fill it), instead of a single-brace {id} you had
to retype inline every time. And sending with a variable still unset now shows
a clear "Set a value for {{siteId}} before sending" prompt, instead of the
confusing "request path escapes the controller's API base" error (an empty
{{token}} was reaching the URL and being refused by the read-only security
gate). (Part of v4.0.0 UniFi API support.)
- **The investigation agent handles large API responses and explores more
efficiently.** A big API response is now truncated intelligently — keeping
whole JSON items plus a "showing N of M — narrow with a query" note, instead
of chopping the body mid-structure into something the model can't parse — with
a larger 32 KB per-response budget. The agent is also guided to not re-read a
GET whose result it already has, to treat a 404 as "that path isn't on this
controller — don't retry it," and to look for a more specific endpoint rather
than re-fetching a summary. Together these help investigations on API sessions
converge instead of looping. (Part of v4.0.0 UniFi API support.)
- The full-screen TUI safety banner (shown when a remote opens vi/nano/top and
keystrokes could act on an unpainted UI) now **stays dismissed for the rest
of the session** once you close it, instead of re-appearing every time a
full-screen tool re-opens. The warning still fires on the first entry per
pane — where the surprise lives — but a nano-heavy session is no longer
nagged on every open (the classic path to warning-blindness). A fresh tab
warns again. (Requested by Jeff Kish.)
Fixed
- The investigation agent no longer loses identifiers in API responses.
UniFi hostId/consoleId values are long hex strings, and the redaction
filter's bare-hex catch-all (meant to net raw secrets in terminal output)
was blanking them as [REDACTED], so the agent couldn't build follow-up
request paths. API (JSON) responses now pass those IDs through while every
key-labeled secret (WLAN PSK, SSH password, RADIUS/API keys) stays redacted;
terminal/CLI redaction is unchanged.
Security
- Hardened the device→LLM redaction boundary for JSON (API) responses so a
controller's secrets never reach the model: credential fields are matched
case-insensitively and by shape (device SSH passwords, WPA passphrases, CA
keys, RADIUS/shared secrets are caught regardless of exact spelling), and
a value containing an escaped quote can no longer leak its tail. Humans
still see raw responses; redaction applies only on the path to the AI.
[3.3.1] - 2026-07-24
Security
- Dependency bumps clearing three advisories flagged 2026-07-24: russh
0.61 → 0.62.4 (the SSH transport — GHSA-g9hv-x236-4qp3 / cqjc-rmpq-xprq /
5xvq-cp9x-6p6r), quinn-proto 0.11.14 → 0.11.16 (GHSA-4w2j-m93h-cj5j),
and brace-expansion 5.0.7 → 5.0.8 (GHSA-mh99-v99m-4gvg, build tooling).
No functional change — the russh bump was compile-, test-, and
live-smoke-clean.
[3.3.0] - 2026-07-24
Changed
- Claude Opus 5 is now the flagship Opus in the Pro and Max tiers (and on
Operator BYOK), replacing Claude Opus 4.8. Opus 4.8 is retired and
transparently aliased to Opus 5 server-side, so existing chats and older
builds keep working with no interruption. Pricing is unchanged ($5/$25 per
MTok); tier budgets and ceilings are unaffected.
[3.2.1] - 2026-07-23
Added
- Open Capture & diff from a session tab. Right-click a session tab →
Compare captures / diff output… opens the capture/diff dialog with that
tab's session pre-selected. It's the same tool that's always been in the
command palette (Cmd/Ctrl+K) — now discoverable without knowing the palette.
[3.2.0] - 2026-07-23
Added
- Per-host accent colors. Assign a device a color from a curated,
theme-aware palette (Add / Edit device → Accent color). The color shows
as a left-edge accent on the sidebar row, the session tab, and the terminal
pane — a quick "am I on prod?" cue. Optional; devices with no color are
unchanged, and the palette adapts to the active theme's light/dark mode.
- Better scrollback search. Cmd/Ctrl+F now highlights every match
(not just the current one), shows a live match counter (e.g. 3/17),
and searches the full 32K-line scrollback the terminal retains — no longer
capped at the front 10K lines.
- Log a session to a file. Right-click a session tab → **Log session to
file…** streams that session's output to a file you pick, each line
timestamped (UTC); a red dot marks a logging tab and Stop logging ends
it. Output is redacted at the write boundary (best-effort, per chunk — like
scrollback export) so a log never captures a device secret in cleartext.
- Capture and diff command output. Command palette → **Compare captures /
diff output** runs a command in an open session, saves its (redacted)
output, and diffs two captures — the same show run over time, or two
devices side by side — to spot config drift.
- Scriptable collections. Save a named set of commands (e.g. an "L3 health
check") and run it against a session in one sweep from the Captures dialog —
each command's output captured for review or diffing. Human input, like the
broadcast bar (not policy-gated).
- Device tags. Tag devices with free-form labels (
prod,core,
datacenter-3) in the Add / Edit dialog — orthogonal to the folder
hierarchy, shown as chips on the sidebar row. (Tag-based sidebar filtering
is a fast-follow.)
- Send Break to a console session. A Break button in the terminal
header of a serial-console session asserts a ~300ms serial BREAK to
interrupt a boot sequence or drop to ROMMON — the classic recovery move
that was previously impossible from the app. Console sessions only.
- Console auto-reconnect. Unplug a USB-serial console cable and plug it
back in and Transit re-opens the dropped session automatically — same tab,
output resumes — instead of leaving a dead "ended" tab. A session you
closed yourself is never reconnected.
Changed
- Broadcast input bar restyled to Transit blue. The broadcast strip
(View → Broadcast Input) was red; it now uses the brand's Transit Blue to
stay on-brand with the rest of the app. The destructive "Interrupt all (^C)"
button keeps a red accent as a blast-radius cue, and the live
"Sending to N of M" device count remains the primary safety indicator.
- Correct wide-character rendering. The terminal now uses Unicode 11
character-width tables, so CJK text, box-drawing, and emoji no longer drift
columns out of alignment.
- Clearer cross-version config error. If
transit.tomlcontains a setting
this build doesn't recognize (usually a file written by a newer Transit),
the loader now tells you to upgrade Transit instead of showing a bare serde
"unknown field" error.
[3.1.0] - 2026-07-22
Added
- BYOK on the Hobbyist tier. Hobbyist now includes Bring Your Own Key:
add your own Anthropic or OpenAI API key and chat with the same
Sonnet 5 / Haiku 4.5 / GPT-5.6 Terra / GPT-5.6 Luna lineup Operator
includes — billed to your provider account, proxied through Transit
Cloud with the same policy gate, approval modal, and redaction as every
cloud model. The model picker now renders BYOK-unlocked models on tiers
with no bundled cloud models, shows a "Cloud — unlock with your API
key" hint listing what a key unlocks, and the empty chat state offers a
one-click jump to Settings → BYOK. (Requires the Transit Cloud rollout;
Opus 4.8 / GPT-5.6 Sol remain Operator-and-up BYOK models.)
- Larger local context windows. Settings → Local models now offers
131,072- and 262,144-token context windows (matching the backend's
validated ceiling and Ollama's own settings range) — the previous UI
stopped at 65,536. The big options are labeled with a RAM/VRAM warning:
the model's KV cache grows with the window.
Changed
- Transit Default theme: Transit Blue primary. Buttons, toggles, and
selection accents now use the brand's Transit Blue (#2A83FE) instead of
teal; the terminal cursor follows. Teal remains in the terminal's ANSI
bright-cyan slot, and the focus ring was already Transit Blue. Pick
"Transit Classic" in Settings → Appearance if you prefer the neutral
pre-refresh look.
[3.0.1] - 2026-07-21
Fixed
- Settings dialog overflow — with all nine sections visible (the
tier-gated BYOK + Local models tabs pushed the count past what the
horizontal strip could hold), the dialog clipped its right edge:
row controls (theme picker, font-size steppers) were cut off and the
About tab was pushed out of view entirely. Settings now uses a
left-hand navigation rail that scales with the section count; the
dialog is a fixed-size workspace and each section scrolls
independently, so the navigation always stays visible.
[3.0.0] - 2026-07-21
Added
- **Bring Your Own Model (BYOM) — local models via Ollama and self-hosted
endpoints.** Chat with models running entirely on your own hardware: the
agent's policy gate, per-command approval modal, and output redaction
apply to local models exactly as they do to cloud ones, and local
conversations never touch Transit's cloud. Zero-config loopback Ollama
support (tools-capable models are auto-detected and grouped under
"Local — your hardware" in the model picker), plus custom endpoints for
remote Ollama or OpenAI-compatible servers (vLLM, LM Studio, llama.cpp,
LiteLLM) — off this machine HTTPS is required, verified against the OS
trust store so enterprise-internal CAs work, with optional bearer tokens
stored write-only in the OS keychain. A cloud-signed offline pass keeps
local models working for up to 7 days without connectivity, so the AI
now works where the terminal always has: on-site, disconnected, and
air-gapped-adjacent networks. Configure under Settings → Local models
(available on every paid tier). Ollama's :cloud-tagged models are
deliberately excluded — they proxy inference through ollama.com, and
local means local. Transit refuses a conversation that would overflow
the local model's context window instead of letting it silently drop
its instructions.
[2.9.0] - 2026-07-15
Added
- Linux builds (Debian/Ubuntu). The release pipeline now ships a
Transit_<version>_amd64.deb (x86_64; Ubuntu 24.04+ / Debian 13+)
alongside the macOS and Windows installers, hosted at
downloads.transitai.app with a stable
/download/linux-deb always-latest link and the same SHA256SUMS.txt
integrity story. In-app auto-update remains macOS/Windows-only — the
Tauri updater can't swap a .deb — so on Linux the update banner and
periodic checks are disabled and Settings → Updates links the downloads
page instead. Browser sign-in round-trips correctly into the running app
(the package ships a desktop entry that passes the transit:// callback
URL through to the app — Exec … %U).
[2.8.1] - 2026-07-15
Added
- Multi-select + "Launch all" in the sessions sidebar. Select
several connections with Shift-click (range) or Cmd/Ctrl-click
(toggle), then right-click → Launch all (N devices); or
right-click a group folder → Launch all in group to open every
connection under it, subgroups included. Tabs appear as each device
connects, a *Connecting… X of N* banner with a Stop button
tracks progress, and one failed device doesn't stop the rest —
failures roll up into a single summary toast. Connects run
sequentially so first-contact host-key prompts and legacy-crypto
approvals appear one at a time.
[2.8.0] - 2026-07-12
Added
- Transit Classic theme — the previous default color scheme,
preserved unchanged as a selectable theme (Settings → Appearance)
for anyone who prefers the original neutral look.
Changed
- New default look — Transit brand colors. The built-in Transit
Default theme now wears the Transit AI brand palette: ink-black
surfaces with subtly raised panels, teal primary buttons, electric-
blue focus rings, and matching terminal accents (teal cursor, brand
blue/cyan ANSI colors). Applies only to the default theme — if you
picked any other theme it is untouched, and the old default lives on
as Transit Classic. The Max-tier account badge also trades
violet for teal (the brand retired purple).
- Editing an SSH-key auth profile now prefills the private-key file
path, so changing the username or passphrase no longer forces
re-browsing for a key file the profile already points at.
[2.7.0] - 2026-07-10
Added
- Multiple button bars — keep separate named button sets (say, a
VOIP bar and a routers-and-switches bar) and flip between them with
the new up/down arrows on the left of the button bar, or jump
straight to one by clicking the bar's name. Right-click the bar for
New / Rename / Delete bar. Your existing buttons carry over
automatically into a "Default" bar; with a single bar the strip
looks exactly as before.
- Per-chat device scope — a new picker in the AI chat header
(next to the model picker) restricts that chat's AI to the devices
you check, the same way the broadcast bar's target list works.
Scope a chat to the two switches you're debugging and the AI can't
see, read, or propose commands against anything else — enforcement
is in the Rust core, not just the UI, and a device you untick mid-
run is cut off immediately (even if an approval dialog was already
open). Default is unchanged: new chats see all devices. Pairs
nicely with multi-chat tabs — one chat per project, each scoped to
its own gear.
- GPT-5.6 family in the model picker (cloud rollout 2026-07-10):
GPT-5.6 Luna (Easy), GPT-5.6 Terra (Medium), and GPT-5.6 Sol
(Advanced). Sol is included on Pro and Max; on Operator it unlocks with
your own OpenAI key (BYOK), the same way Opus 4.8 does with an Anthropic
key. GPT-5.5 and GPT-5.4 mini retired — existing chats and stale
selections are served transparently by the closest 5.6 successor, and
the picker refreshes automatically.
[2.6.3] - 2026-07-09
Added
- The multi-line paste dialog's editor grew a Find & Replace row for
adapting pasted config templates before they're sent — swap a hostname,
VLAN, or IP across dozens of lines without leaving the confirm step.
Open it with the Find & replace button or Cmd/Ctrl+F while the
dialog is up. Matching is literal (no regex), with a live "2 of 17"
match counter, Match case and Whole word toggles (whole-word
treats / . : - as boundaries, so replacing 0/0/1 doesn't also
hit 0/0/10), Enter / Shift+Enter (or F3 / Shift+F3) to step through
matches, and Replace / Replace all with a one-click Undo.
Escape closes the find row first, the dialog second. The dialog is
wider and the editor no longer soft-wraps long config lines (it scrolls
horizontally instead). The safety property is unchanged: what you paste
is exactly what's sent — edits, replacements and all.
[2.6.2] - 2026-07-07
Added
- Host-key rotation is now handled in-app. When a device's SSH host key
changes since the last connect (re-image, RMA, firmware re-key), Transit
shows a changed-key warning dialog with the pinned and new fingerprints
side by side instead of a dead-end error that pointed at hand-editing
known_hosts.toml. Replacing the pin takes two deliberate steps — tick
"I've verified this key change is legitimate", then the red
Replace & connect — and the pin is rewritten only after the
connection also authenticates, so a failed login never displaces a
good pin. Declining (or any attempt to dismiss the dialog) leaves the
old pin untouched and fails the connect with the familiar mismatch
error. There is intentionally no "remember" shortcut: every key change
gets its own confirmation.
[2.6.1] - 2026-07-07
Added
- Operator tier can now use Claude Opus 4.8 when BYOK is on with an
Anthropic key enrolled — the model runs on your own key, so it's
available without upgrading. The chat model picker shows Opus only
when BYOK is active for Anthropic; a hint points at Settings → BYOK
otherwise. Turning BYOK off (or clearing the key) mid-chat switches
the chat back to Sonnet with a notice, and a cloud rejection now
reads "Opus needs your own Anthropic key" instead of a generic
plan error. Requires the matching cloud release.
[2.6.0] - 2026-07-07
Added
- Free-trial support (dormant until the cloud launch flip):
/menow decodes
the cloud's trial block; a bottom-left banner shows "N days left in your
trial" with an Upgrade Now action, and Settings → Billing gains a trial row +
Upgrade Now. Inert while the cloud's TRIAL_ENABLED flag is off — no UI
change for current users.
Changed
- The bottom-left cards (update prompt, customer notice, trial countdown) now
stack in a single column that packs toward the corner — no more floating
gaps when one of them is dismissed or snoozed.
[2.5.0] - 2026-07-06
Added
- Multiple concurrent AI chat tabs. The chat panel now supports several
chats at once — a tab strip with a + button (also ⌘/Ctrl+T or the
command palette's "New chat"), each tab its own conversation running its own
agent loop. Double-click a tab to rename it; the model picker is per-chat.
Chats keep running in the background — a long agent task in one tab keeps
going while you work in another, or even while the chat panel is collapsed.
- Cross-chat notifications. A chat that isn't the one you're looking at
surfaces a stacking, clickable card (bottom-right) and a tab dot —
amber when it needs command approval, green when its task finishes. Click
the card to jump straight to that chat. Approval always happens in that
chat's own modal (never a stolen pop-up), so two chats needing approval at
once can't collide.
- A setting (on by default) controls whether a completed prompt in an
unfocused tab raises a notification card.
[2.4.0] - 2026-07-06
Added
- Broadcast input bar — send a command to all sessions at once
(SecureCRT-style). Enable it from View → Broadcast Input: a bar appears
at the bottom where a line you type is sent to every open session
simultaneously (press Enter). It targets all live sessions by default, with
a selector to exclude specific ones (e.g. a production box) and a live
"Sending to N of M" device count. A mouse-only Interrupt all (^C) button
sends Ctrl-C to every target — normal Ctrl+C in a terminal still goes only
to that one session. The bar is deliberately loud and red: it's human input
going to many devices at once, so the visible count is your confirmation.
Fixed
- **App content no longer shifts left / clips its first column when the tab
strip scrolls.** After opening enough sessions for the scrollable tab
strip's arrows to show (v2.3.4), the whole workspace could shift a few
pixels left — clipping the first character of the sidebar entries, the tab
labels, and the terminal prompt (e.g. AZ104-SW06-22> showed as
Z104-SW06-22>). Cause: the tab strip's "keep the active tab visible"
logic used scrollIntoView, which scrolls *every* scrollable ancestor;
combined with a stray pixel of horizontal overflow in the shell layout, it
nudged the entire app sideways. The reveal now scrolls only the tab strip
itself, and the layout is hardened so nothing but the tab strip can scroll
horizontally. (Previously the only workaround was toggling the button bar
off and on, which reset the scroll.)
[2.3.5] - 2026-07-05
Changed
- Clearer error when a device sends a malformed SSH handshake. Some
switch firmware builds emit a key-exchange field that isn't valid
ASCII/UTF-8 (which the SSH standard doesn't permit), causing the
handshake to fail before any connection can be negotiated. Transit now
reports this as an actionable message pointing at a device firmware
update, instead of a cryptic low-level "character encoding invalid"
error. There is no in-app workaround — the malformed data arrives before
Transit can act — so a firmware update on the device is the resolution.
[2.3.4] - 2026-07-05
Added
- Close all sessions. A "Close all tabs" item on the tab right-click
menu disconnects every open session and clears the strip in one action,
with a single confirmation summarizing how many are still connected (or
no dialog at all when every tab has already ended). Requested by a user
running dozens of switch sessions at once.
- Scrollable tab strip. When open tabs overflow the window, left/right
chevron buttons appear (MTPuTTY-style) to page through them; the active
tab always scrolls into view, and trackpad/horizontal-wheel scrolling
works too. Previously the strip clipped tabs off the right edge.
- Scrollable button bar. The SecureCRT-style button bar is now a single
horizontally scrollable row with the same chevron affordance, instead of
wrapping into extra rows that ate terminal height.
[2.3.3] - 2026-07-04
Fixed
- **Legacy SSH: group-exchange-only switches connect after the weak-crypto
opt-in.** The legacy (weak-crypto) path now requests Diffie-Hellman
group-exchange bounds a 2048-bit-era server can satisfy (min/preferred
2048; previously russh's default min 3072). BDCOM-based FS.com campus
switches that offer only diffie-hellman-group-exchange-sha1 answered
the old request by disconnecting mid-handshake — the same error as
before the opt-in, so "Connect Anyway" appeared to do nothing. 2048-bit
GEX matches the group14-sha1 strength the legacy list already
accepts; the strict path keeps russh's defaults.
Changed
- Connect errors now carry the device's own disconnect reason. When a
device refuses the SSH handshake with a protocol-level disconnect
message, Transit surfaces that text (sanitized, length-capped) in the
connect error instead of a bare "server disconnected during handshake"
— so the error names the algorithm slot the device couldn't match,
whenever the device says so.
- Honest error when the opt-in isn't enough. The handshake-interrupted
error no longer advises "allow weak crypto when prompted" (it can only
appear after weak crypto was already allowed); it now explains that the
device refused even the legacy algorithm set and points at device SSH
settings/firmware or a firewall/ACL.
[2.3.2] - 2026-07-04
Fixed
- Legacy switches now actually connect after "Connect Anyway." v2.3.0
started showing the weak-crypto prompt for switches that drop the SSH
handshake (Cisco SG300/SG500, FS.com S5500), but the retry still failed with
"handshake … interrupted before algorithm negotiation completed (key exchange
init failed)." The cause was key-exchange preference: the legacy algorithm
list offered Diffie-Hellman group-exchange before the fixed groups,
and these switches answer a group-exchange request with a 1024-bit modulus —
below the 2048-bit floor our SSH library enforces — so the exchange failed (or
the switch dropped the connection) every time. Transit now prefers the
fixed-group group14-sha1/group1-sha1 exchanges (which these switches also
advertise) over group-exchange on the legacy path, so the opt-in completes the
handshake. Weak crypto is still never used without the explicit per-device
prompt, and the strict default handshake is unchanged.
[2.3.1] - 2026-07-03
Fixed
- Windows: "Hide" no longer makes the window disappear with no way back.
The Transit menu carried macOS-only Hide / Hide Others / Show All items on
Windows and Linux, where they have no equivalent — on Windows, "Hide" hid the
window with no Dock, tray, or "Show All" to restore it, so Transit kept
running invisibly and only Task Manager → End task recovered it. Those three
items are now macOS-only; on Windows/Linux the Transit menu is **About +
Exit**, and you minimize/restore the window the normal way. (Thanks to the
customer who reported this on Windows Server 2019.)
[2.3.0] - 2026-07-03
Added
- Export your sessions to CSV. Right-click anywhere in the sessions
sidebar — the empty area, a device, or a group folder — and choose
Export sessions… to save every connection to a CSV. The file uses the
same columns Transit imports (`name,host,port,username,vendor,group,
key_path`), so it round-trips: export from one machine, import on another
(or back up your inventory). As with import, **secrets are never
exported** — the CSV carries only usernames and key-file paths, never a
password or key passphrase.
Fixed
- **Connecting to legacy switches that require older SSH algorithms now
works.** Some older gear — Cisco SG300/SG500 small-business switches,
FS.com S5500 switches — drops the SSH connection during the handshake
instead of negotiating, because it offers only SHA-1 key exchange
(diffie-hellman-group1-sha1, diffie-hellman-group-exchange-sha1) or
ssh-rsa host keys. Transit used to surface this as a dead-end "Key
exchange init failed" / "Disconnected" error with no way forward. It now
recognizes it as a possible legacy-crypto requirement and shows the same
per-device weak-crypto opt-in prompt used for other legacy devices —
approve it (optionally "remember for this device") and the connection
retries with the legacy algorithm set. Weak crypto is still never enabled
silently, and a genuinely unrelated failure surfaces its real error after
the retry rather than being masked.
- "About Transit" now works on Windows. The App → About Transit menu
item did nothing on Windows (it worked fine on macOS). It now opens the
About page (Settings → About) with the version and license. macOS keeps
its native About panel.
[2.2.7] - 2026-07-02
Added
- Import your MTPuTTY and MobaXterm connections. The Import wizard
(sidebar → Import, or ⌘K → "Import connections…") now reads MTPuTTY
server lists (mtputty.xml) and MobaXterm bookmarks (MobaXterm.ini
or a .mxtsessions export) alongside SecureCRT, OpenSSH ssh_config,
and CSV. Hosts, ports, usernames, folder hierarchy, and key-file paths
come across; SSH sessions import, and anything else (telnet/RDP/VNC/
serial, or MTPuTTY entries whose details live in a PuTTY saved session
in the Windows registry) is listed in the preview as skipped so nothing
disappears silently. As with every import source, **stored passwords are
never read or decrypted** — they stay in the source app, and you map
each deduped login to a Transit auth profile once.
Changed
- **The terminal is free — signing in without a subscription no longer hides
the workspace.** Previously, a signed-in account with no active plan saw a
full-screen "Subscribe to use Transit AI" panel in place of the entire app.
The workspace (terminal, sessions, inventory) now always renders; the
subscribe prompt lives inside the chat panel, since only the AI assistant
requires a plan. Use Transit as a standard SSH/serial terminal at no cost.
[2.2.5] - 2026-07-01
Security
- Policy gate hardening (defense-in-depth). Strengthened the per-vendor
read-only command gate: it now denies native output redirection
(> / >>), catches a blocked pipe stage even when it is hidden behind
a quote (network CLIs don't parse shell quoting the way the gate's
allow-matcher does), tightens NX-OS | sort (write/exec flags),
backports the Cisco/Arista show tech-support <destination> block from
IOS-XR, and blocks Junos monitor … write-file. Every agent-proposed
command already requires explicit per-command user approval (Rule 3);
these refinements harden the automated gate that runs ahead of it.
- Broader redaction coverage. Expanded the device-output → AI
redaction filter to more credential shapes: IPsec pre-shared keys
carrying an encryption-type token (`pre-shared-key local|remote 0|6
<psk>), modern OpenAI project keys (sk-proj-…`), SNMP community strings
on snmp-server host trap targets, credentials embedded in
connection-string / URL userinfo (scheme://user:PASSWORD@host), HTTP
Basic Authorization headers, and wireless/WPA pre-shared keys.
- Terminal paste review. The multi-line paste confirmation dialog now
reliably intercepts keyboard paste (Cmd/Ctrl+V), so multi-line content is
always reviewed before it reaches the device.
- Additional hardening. On-disk SSH private-key material is zeroized
from memory after use; the inventory loader rejects plaintext secrets
regardless of TOML key spelling (bare, quoted, or dotted); the SSH
connection's compile-time thread-safety assertion now covers its full
captured set; and the release build's symbol scan fails closed on a
stripped binary.
[2.2.4] - 2026-07-01
Changed
- Higher limits for importing large connection sets. Raised the
connection-import file cap (SecureCRT SCRTConfig.xml / OpenSSH
ssh_config / CSV) from 8 MiB to 64 MiB, and the inventory file cap
from 256 KiB to 4 MiB (~10k+ devices). Importing hundreds-to-thousands
of sessions no longer trips a "file is too large to import" error or an
inventory-size ceiling.
[2.2.3] - 2026-07-01
Security
- Further enhancements to modern secret redactions. Extends the
device-output → AI redaction filter beyond device credentials to
cover common cloud/SaaS API tokens (GitHub, Stripe, Slack, OpenAI,
GitLab, and Google API keys), plus cleartext line/console and VTP
passwords and modern password-hash formats, so more secret material
is masked before it can reach the AI. Redaction remains one layer of
defense-in-depth alongside the per-command policy gate and approval
modal.
[2.2.2] - 2026-06-30
Security
- Enhanced vendor-specific redaction filter. Broader, more reliable
redaction of platform-specific credential formats in device output
before it reaches the AI — covering password hashes, VPN pre-shared
keys, and BGP/OSPF/IS-IS/EIGRP routing-authentication secrets across
all supported platforms (Cisco IOS/IOS-XE/IOS-XR/NX-OS, Juniper Junos,
Arista EOS, and Palo Alto PAN-OS), plus a vendor-agnostic catch-all for
standard password-hash formats regardless of the surrounding command.
[2.2.1] - 2026-06-30
Fixed
- You can now install an update from Settings → Updates. "Check for
updates" there correctly detected new versions but offered no way to
install one — it now shows a Download & Install button (with inline
download/install progress) whenever an update is available, matching the
bottom-left prompt.
- The update prompt no longer disappears forever after "Later." "Later"
now means "not right now, maybe next launch" — the prompt re-appears the
next time you open the app while the update is still available. A new
Skip this version action permanently dismisses one specific version
(and only that one — a newer release still notifies you).
[2.2.0] - 2026-06-30
Added
- Claude Sonnet 5. Transit now offers Claude Sonnet 5 — the new default
Sonnet for new chats across all plans. It's priced the same as Sonnet 4.6,
with a newer knowledge cutoff (January 2026) and the same 1M-token context.
Claude Sonnet 4.6 remains available in the model picker, and existing chats
keep whatever model you selected.
Changed
- Agent auto-approve is now chat-scoped, with a clearer approval modal.
The "auto-approve a matching regex" affordance in the command-approval
modal now persists for the life of the chat (cleared when the chat
closes) instead of resetting after every message — approve ^show once
and it holds for the rest of the investigation. It sits behind a
clearly-labeled, collapsed **"Auto-approve matching commands? Expand
here"** disclosure with its own dedicated button — kept deliberately
separate from the primary Approve so it can't be armed by a reflex click
(modal-fatigue mitigation, threat-model T18) — and the regex field is
pre-filled with ^show. The per-vendor policy gate still runs on every command
regardless, and the affordance stays hidden/refused for generic-Linux
(unrestricted) and custom (BYOP) vendors, which require a per-command
click. Also closes a gap where a custom-vendor auto-approve was silently
ignored backend-side.
[2.1.0] - 2026-06-29
Added
- Cisco IOS-XR command policy — seventh gated vendor. Read-only gate for
Cisco's carrier-grade OS (ASR 9000 / NCS / CRS / XRv), with XR-specific
shell-escape blocks: run (classic 32-bit/QNX task shell), bash (64-bit
eXR Linux root shell), tclsh, script (XR-7.x script run on-box
Python/bash automation), admin (System Admin VM), and attach
(per-node shell). Encodes the two-stage commit config model (configure /
commit blocked; XR has no write verb), hardens show tech-support
against its file-writing forms, and pipe-blocks the write/escape stages
(| file, | redirect, | utility, | tee, | append). Select it per
device via the inventory vendor cisco_ios_xr. Verified by an
allowed/blocked corpus, a no-bypass proptest, and cargo-mutants on the gate.
[2.0.1] - 2026-06-28
Added
- ITInspired themes — new light and dark color schemes (Settings →
Appearance) based on the itinspired.com brand:
leaf-green (#74b843) primary with cyan (#00baff) focus accents — light
on warm white, dark on charcoal.
[2.0.0] - 2026-06-28
This release adds a version-aware Terms & Privacy consent gate. Signed-in
users who have not affirmatively accepted the current Terms of Service and
Privacy Policy — anyone who signed up before the sign-up consent checkbox
existed, and everyone after a future Terms change — are shown a one-time
blocking screen and must click I Agree before using the app. Acceptance is
recorded server-side as an auditable consent record.
Added
- Terms & Privacy consent gate. A blocking, non-dismissible screen replaces
the workspace when the signed-in account hasn't accepted the current
Terms/Privacy version. It links to the live Terms and Privacy pages and
records an affirmative "I Agree" before the app unlocks. New accounts that
accept at sign-up never see it; a future Terms revision re-shows it to
everyone exactly once.
[1.6.5] - 2026-06-26
This release rolls up the work versioned 1.6.4 (which was never tagged for
production) together with the multi-line-paste focus fix.
Fixed
- **Clear-terminal shortcut (⌘⇧K / Ctrl+Shift+K) now works on Windows and
Linux.** It previously only fired on macOS: the keystroke was wired solely to
the native menu accelerator, which the focused terminal swallows on
Windows/Linux (only macOS's global menu bar intercepts it first). Worse, when
the terminal had focus the chord was sent to the device as a Ctrl+K
kill-line instead of clearing. The shortcut is now handled in the app itself,
so it clears the active session on every platform — and no longer leaks a
keystroke to the remote device.
- The terminal cursor no longer disappears after a multi-line paste.
Confirming (or cancelling) the multi-line paste dialog left keyboard focus
on nothing, so the cursor went hollow and you had to click back into the
terminal before you could type or press Enter. Focus now returns to the
active terminal on every way of closing that dialog.
[1.6.3] - 2026-06-25
Changed
- The "Approve command?" dialog now identifies the session by its tab name
(e.g. vEX1, or your custom rename) instead of an internal identifier, so
it's clear which open session the agent wants to run a command in. The full
session id remains available on hover.
[1.6.2] - 2026-06-25
Added
- A keyboard shortcut to clear the terminal. Press ⌘⇧K (Ctrl+Shift+K
on Windows/Linux), or use the new View → Clear Terminal menu item, to clear
the active session's screen and scrollback — the same action already on the
tab's right-click menu.
Changed
- A clearer notice when AI is paused by the usage safety limit. If a burst of
unusually high usage trips Transit's safety limit, the chat now shows a calm
banner that explains it's a protective pause (not an outage), counts down to the
automatic unlock (~15 minutes), and offers a one-click Resume now — replacing
the old generic "Transit Cloud is temporarily paused" error. Heavy Operator/Pro
users also see a hint that a higher plan includes more headroom.
[1.6.1] - 2026-06-25
Added
- Bulk import now sets up your key-based logins for you. When you
import from SecureCRT / ssh_config / CSV, every login that uses an
on-disk SSH key or an SSH agent can become a working auth profile in one
click. Transit checks each referenced key file (read-only) and, for
encrypted keys, asks for the passphrase right in the credential step —
saving it to your OS keychain (never the inventory file). Creating a
profile by hand is prefilled too: + New opens already set to "SSH key
file" with the detected path and username filled in.
Fixed
- The import "Map credentials" step now fills the window instead of a
narrow centered column, so long SSH key paths are fully visible (no more
truncated /Users/…/id_ed25519).
[1.6.0] - 2026-06-24
Added
- Sign in with an SSH key file (SecureCRT-style). Create an auth
profile that points at a private key on disk — pick it with a file
browser, no ssh-agent setup required (a relief on Windows
especially). OpenSSH, PEM, and PuTTY .ppk keys all work; if the key
has a passphrase, enter it once and it's saved to your OS keychain
(never the inventory file). The key file stays where it is — Transit
stores only its path.
[1.5.1] - 2026-06-24
Fixed
- **A half-typed command is no longer garbled when you switch session
tabs.** Typing a line without pressing Enter, switching to another
tab, and switching back could leave the prompt text and cursor
corrupted (e.g. R1#This is a line came back as R1#This i). Hidden
tabs are no longer re-measured while collapsed, so the in-progress
input line survives the round trip.
[1.5.0] - 2026-06-23
Added
- Works behind corporate TLS inspection. Transit's connection to Transit
Cloud now trusts your operating system's certificate store by default, so it
keeps working on networks that inspect TLS traffic — a firewall's CA installed
in your system keychain/store is honored. A new Settings → Network tab adds
a Strict TLS toggle (off by default) that, when on, trusts only the
built-in public certificate authorities and refuses any inspected connection.
Takes effect on the next launch. SSH device connections use a separate trust
model and are unaffected.
- Actionable certificate errors. When the server certificate can't be
verified, the account area now shows a clear message that deep-links to
Settings → Network, instead of an opaque transport error.
Changed
- Settings is now a gear in the sidebar. Opening Settings is a one-click
gear next to the account chip, rather than hidden inside the account popover.
Fixed
- Terminal focus when switching session tabs. Clicking another session's tab
(e.g. R1 → R2) now puts the cursor in that terminal immediately, instead of
requiring a second click into the pane. The v1.4.1 fix focused the pane the
moment it activated — before it was laid out and before the tab click released
DOM focus — so the focus didn't land; it's now deferred a frame so it sticks.
(The v1.4.1 button-bar focus hand-back was unaffected and keeps working.)
[1.4.1] - 2026-06-22
Fixed
- Terminal focus on tab click. Clicking a session tab now puts the cursor
in that terminal immediately, so you can type without a second click into the
pane.
- Terminal focus after a button-bar press. Sending a macro from the button
bar now returns focus to the active terminal (the button click no longer
leaves the cursor on the button).
- "New device in this group" now pre-fills the group. Choosing *New device
in this group…* from a group's context menu correctly seeds the Group/Folder
field. Previously the field came up blank because the dialog stayed mounted
and ignored the group on reopen.
Changed
- Clearer New/Edit device dialog labels. *ID* → Friendly Name (hint
*Router1*), *Port* → SSH Port (Transit is SSH-only), *Vendor* → **Vendor
— Policy Gate** (it selects the command policy gate, not just a label), and
*Group* → Group/Folder.
[1.4.0] - 2026-06-19
Added
- Clear terminal. Right-click a session tab → Clear terminal wipes the
visible terminal output and resets that session's backend scrollback ring, so
the embedded agent's read_scrollback returns only post-clear output. Works
for both SSH and serial-console sessions. (A keyboard shortcut may follow.)
- Confirm before disconnecting a live session. The pane's Disconnect
button now asks first when the session is still connected, so a misclick can't
silently drop the connection. An already-ended tab's Close button is
unchanged (no prompt).
- Warn before quitting with an active session. Quitting Transit — via
Cmd+Q or the window-close button — while an SSH/console session is still
connected pops a "Quit anyway?" confirm instead of silently dropping the
connection. Anchored to true liveness: a tab you logout/exit-ed from (its
channel is dead, even if the tab lingers) is safe and does not prompt.
- Button bar (SecureCRT-style). A configurable toolbar of command buttons,
toggled from the new View → Button Bar menu. Each button sends a string to
the active session with SecureCRT's "Send String" escape codes — \r (Enter),
\n (newline), \p (1-second pause), \v (paste clipboard), \e/\###
(ESC/octal), \\ (literal backslash) — so one button can fire a full command
plus Enter, or a multi-step macro. Right-click the bar to add a button or hide
it; right-click a button to edit or delete. Buttons persist locally. (v1 ships
a single shared bar; multiple named bars may follow.)
- Native application menu. Transit gains a proper menu bar (App · Edit ·
View · Window) — primarily to host View → Button Bar, with the standard
Quit / Copy / Paste / Undo / Hide items so the usual keyboard shortcuts keep
working.
[1.3.3] - 2026-06-18
Changed
- Clearer labels in the New/Edit Auth Profile dialog. Renamed fields
and dropdown options for plain-language clarity — "Transit Friendly
Name", "OS keychain (passwords)", "SSH agent (ssh-agent, 1Password,
etc.)", "OS Keyring Friendly Name", "Password Value" — and the username
placeholder now shows root. Display-only; no change to stored
credentials or transit.toml.
[1.3.2] - 2026-06-18
Fixed
- **1Password SSH keys now work without manual
SSH_AUTH_SOCKsetup on
macOS.** When a connection pins a key fingerprint and that key isn't in
the agent SSH_AUTH_SOCK points at — on macOS that's Apple's built-in
agent by default, which shadows 1Password — Transit now also checks
1Password's well-known agent socket automatically. The private key never
leaves 1Password, and every signature is still gated by 1Password's
approval. When a key still can't be found, the error now pinpoints the
cause (agent not enabled vs. 1Password locked vs. fingerprint mismatch)
instead of a generic "not available."
[1.3.1] - 2026-06-18
Fixed
- Connect to SSH hosts that require keyboard-interactive authentication —
notably VMware ESXi, and any host configured with the SSH password
method disabled (PasswordAuthentication no + `KbdInteractiveAuthentication
yes`). Transit now answers the server's keyboard-interactive prompts with
your saved password — exactly as the OpenSSH command-line client does —
instead of failing with "authentication failed … server rejected the
credential." Public-key (SSH agent) connections are unchanged.
[1.3.0] - 2026-06-16
Added
- Import connections from other clients. Bring an existing fleet into
Transit in one pass instead of re-entering it by hand. The Import button
in the sidebar header (and on the welcome screen, or ⌘K → Import) reads
SecureCRT (an exported SCRTConfig.xml), an OpenSSH ~/.ssh/config,
or a CSV, then walks you through three steps: it groups your saved logins
so you map each shared credential once — reuse an auth profile you already
made, or create one (the secret goes straight to your OS keychain) — then
shows every connection in an editable grid where you can bulk-assign vendor
and group, rename, and exclude rows before importing. Transit reads host,
port, username, folder structure, and key-file paths; it never reads or
decrypts your stored passwords. Devices that collide with an existing name are
flagged and skipped until you rename them, and the whole import is atomic —
if anything is wrong, nothing is written.
[1.2.0] - 2026-06-15
Added
- In-app notices. Transit can now surface short announcements — a
changelog, a newly available model, or an important account or policy
notice — as a dismissible card in the bottom-left corner, fetched
alongside your account info. Only the highest-priority unread notice
shows at a time, and dismissing one is remembered. Notices are
delivered from Transit's service, so they reach installed builds
without waiting for an app update.
[1.1.0] - 2026-06-13
Added
- Connections pane group management. Organize the sidebar from the
GUI: right-click → New group (empty groups now persist), **New
subgroup, Rename, and Delete group** (its connections and
subgroups move up to the parent — nothing is deleted). **Drag a
connection** from one group into another, or onto the "Drop here to
ungroup" zone. Group expand/collapse state is remembered across
launches. Backed by a small groups registry in transit.toml (so a
device-less group survives) layered over the existing per-device group
path; pre-existing inventories load unchanged.
- Chat font size. Settings → General gains a chat font-size control
(+/− / value / Reset) alongside the terminal font-size row. It scales
the agent chat panel's message thread — prose, code blocks, and inline
code — independently of the terminal, defaulting to 14px (prose reads a
touch larger than the monospace terminal default). Persisted to
localStorage like the terminal preferences.
[1.0.2] - 2026-06-12
Added
- Terminal font picker. Settings → General's font field is now a
dropdown of the monospace fonts actually installed on your machine —
and filtered to the ones the terminal renderer can really use, so
families the OS ships but withholds from app web content (SF Mono)
no longer appear just to silently fall back. Each option previews in
its own face. Custom… keeps the previous free-text path for
hand-written fallback stacks and fonts that don't advertise fixed
pitch.
- Editable paste confirmation. The multi-line paste dialog now lets
you edit the pending text before sending — trim a stray trailing
newline, drop a line, fix a typo — instead of cancelling and
re-staging the whole paste. What you paste is exactly what's in the
box, the line count updates live, and emptying the box disables
Paste.
Changed
- Wider Settings dialog (672 → 896 px max) so the General and
Policies tabs stop crowding their controls.
Fixed
- Connections sidebar: host:port no longer clips. Two layers. The
real culprit: the sidebar's scroll viewport sized its content to the
widest row, so one long hostname pushed every row's right-aligned
address past the visible edge — the viewport's content wrapper is
now pinned to the sidebar width. Within a row, the address also
keeps a readable minimum width, truncates predictably, and both
fields show their full value on hover.
[1.0.1] - 2026-06-11
Added
- Terminal font setting. Settings → General gains a font-family field —
type the name of any monospace font installed on your machine (e.g.
JetBrains Mono) and every terminal pane switches live. Falls back to the
stock font stack when the field is empty or the font isn't installed.
- Per-vendor syntax-highlighting packs. When a device opts into syntax
highlighting, vendor-specific vocabulary now layers over the generic set:
Cisco IOS / IOS-XE / NX-OS / Arista EOS get syslog mnemonics colored by
severity (%SYS-2-… red, %LINK-3-… yellow, %SYS-5-… cyan) plus
connected / notconnect / err-disabled interface status; Juniper Junos
gets commit complete, the truncated BGP Establ state, and chassis-alarm
classes. Picked automatically from the device's vendor.
Fixed
- Terminal bottom row no longer clips after font zooming. Changing the
font size (⌘+ / ⌘− / ⌘0) or family re-fits the pane on the next frame, after
the renderer's cell metrics settle — previously repeated zooming could push
the prompt line below the visible area until the window was resized.
Changed
- Claude Opus 4.7 retired from the model picker — superseded by Claude
Opus 4.8 (same speed tier and price). Chats still set to Opus 4.7 are served
by Opus 4.8 automatically; no action needed.
Security
- PAN-OS policy: viewer commands grammar-anchored. The
less/tail/
find / grep allow-rules now require PAN-OS's own grammar (a …-log area
for the first three, the literal find command form), so their GNU
namesakes (less /etc/passwd, find / -exec …) can no longer satisfy the
allowlist on a mislabeled device. Defense-in-depth — such commands were
already subject to the approval modal.
[1.0.0] - 2026-06-10
First stable release. Headline features: Bring Your Own Policy, custom
vendors, connection-name-aware AI, and open-session-scoped policy briefing.
Added
- The AI assistant now knows your connections by name. Sessions surface
the connection name you gave the device (its inventory id, e.g. "R1")
instead of a host:port stand-in, so "what is R1's loopback IP?" resolves
to the right session. The session list the assistant sees also includes
each device's vendor.
- Bring Your Own Policy (BYOP). Supply your own command policies, layered
over the built-in ones: add read-only allowed commands to a shipped vendor,
or define an entirely new vendor (e.g. Fortinet, MikroTik) with its own
<vendor>.yaml. Point Transit at a policy directory (the Vendor field in
the device dialog accepts a custom name; set the directory via
TRANSIT_USER_POLICIES or the Settings → Policies tab). The directory can
live on a shared drive for team use. Your additions can never weaken the
built-in safety floor — a shipped block (config mode, write commands, shell
escapes) stays blocked no matter what a user policy says — and a custom
vendor still requires per-command approval for every command.
- Sample policies for popular vendors (
policies/samples/): vetted
read-only starting points for Fortinet FortiOS and MikroTik RouterOS,
ready to drop into your BYOP policy directory and doubling as worked
examples of the policy schema.
Changed
- The AI assistant's policy briefing is now scoped to your open sessions.
The system prompt includes only the command policies for vendors you
currently have sessions to (plus an explicit default-deny note for devices
with no policy), instead of every shipped vendor's full policy on every
conversation. Cuts per-turn token overhead and clears the path to a much
larger vendor catalog; enforcement is unchanged — every proposed command
still runs the full policy gate and the approval modal (Rule 3).
[0.3.0] - 2026-06-09
Security-hardening release resolving the findings of an internal code review.
Security
- The AI command gate can no longer be tricked by multi-line commands. A
proposed command that tried to hide a second statement behind a newline (or
other control character) is now rejected before it is evaluated, the approval
modal shows the full command faithfully instead of collapsing hidden lines,
and the SSH/serial executors refuse to send control-character payloads.
Command matching is now case-insensitive, so block rules can't be sidestepped
with alternate capitalization.
- Stronger device-output redaction. Added high-entropy key/hash catch-alls
and coverage for key chain key-strings and PPP passwords, and redaction now
runs over the full buffer before any truncation — so a secret split across a
buffer boundary can no longer slip through to the AI.
- Sign-in tokens are no longer written to logs. The desktop stopped logging
the transit:// sign-in callback URL (which carried access/refresh tokens),
and the logging subsystem is now actually initialized.
Fixed
- More resilient cloud connections: requests now time out instead of hanging,
a transient server blip during token refresh no longer signs you out, and
simultaneous refreshes are coalesced.
- Out-of-quota, rate-limit, spend-pause, and unavailable-model responses now
show a clear message in chat instead of a generic status code.
- SSH sessions: a close signal could occasionally be missed (leaving a tab that
never showed as closed); one stuck session could freeze the others; and
carefully verifying a new host key no longer risks a spurious connect timeout.
- The inventory editor no longer errors on hand-written inline-table TOML,
editing a device preserves a remembered "allow weak crypto" choice, and
multibyte terminal output split across packets now renders correctly.
[0.2.2] - 2026-06-07
Added
- Claude Opus 4.8 in the chat model picker (under Advanced) —
Anthropic's most capable model, at the same speed tier and price as
Opus 4.7.
[0.2.1] - 2026-06-05
Added
- New color theme: Transit Twilight — an original dark scheme (deep
twilight indigo with teal and amber accents). Pick it in Settings →
General → Theme.
[0.2.0] - 2026-06-05
Added
- Automatic updates. Transit now checks for a new version on launch and
shows a small prompt in the bottom-left corner when one is available. Click
Install & Restart and Transit downloads the update, verifies its
signature, swaps itself in place, and relaunches — no manual reinstall.
Choose Later to be reminded at the next release. Settings → Updates shows
your current status and a manual Check for updates button. (macOS Apple
Silicon and Windows.)
Changed
- The AI investigation loop no longer stops every dozen rounds and makes
you type "continue". It now runs continuously through an investigation
and only pauses for a one-click Continue after a long autonomous
burst (~50 commands), with an always-visible Stop and a live activity
readout (commands run · elapsed · tokens). A per-turn timeout guards a
stalled model response. Large command / scrollback outputs are capped,
and older ones collapse to a re-readable note, so long log-parsing
sessions stay responsive instead of degrading.
[0.1.2] - 2026-06-01
Changed
- Upgraded the terminal to xterm.js 6 — rendering now uses the WebGL addon
(with an automatic fallback to the DOM renderer on GPU context loss).
- Migrated the styling pipeline to Tailwind CSS v4.
[0.1.1] - 2026-06-01
Changed
- Refreshed Rust dependencies (
age0.11,toml1.x,toml_edit0.25,
dirs 6, getrandom 0.4, tauri 2.11.2, and related transitive
updates). Encrypted session export migrated to age 0.11's API with no
change to the on-disk format — exported files stay decryptable with
age -d (scrypt KDF + ChaCha20-Poly1305).
- Refreshed frontend dependencies — notably TypeScript 6, lucide-react 1,
and lint-staged 17, plus minor TanStack Query, React Hook Form, ESLint,
Vite, and Vitest updates. No user-facing behavior change.
[0.1.0] - 2026-05-31
Added
- Cross-platform GUI SSH client (Apple Silicon macOS + Windows x64): xterm.js
terminal, multi-session tabs, host-key trust-on-first-use, a modern-crypto
handshake with a per-device legacy opt-in, and optional per-device syntax
highlighting and SecureCRT-style quick copy/paste.
- Embedded read-only AI investigation agent with a fixed four-tool surface, a
per-vendor command policy gate, and a device-output redaction filter on
everything the model sees.
- Shipped vendor policies: Juniper Junos; Cisco IOS, IOS-XE, NX-OS; Arista
EOS; Palo Alto PAN-OS; plus an unrestricted generic-Linux profile.
- Transit Cloud account flow: Clerk sign-in, subscription billing, and
bring-your-own-key (BYOK) support on paid tiers.
- Signed + notarized macOS
.dmgand Authenticode-signed Windows.msi/
NSIS -setup.exe installers, distributed via the dev and prod release
channels.