- feat: live tunnel throughput on Linux, parity with macOS.
- feat: detail panel on Linux now shows real bytes-per-second per client process via a direct kernel netlink call (NETLINK_SOCK_DIAG), alongside the channel-events swimlane and per-client roster you already had.
- change: ROUTE card uses a dotted vertical connector and a fisheye marker on the destination so multi-hop chains read clearly without relying on colour.
- fix: long PATTERN MATCH header lists wrap across multiple rows instead of overflowing the detail panel border.
- feat: hosts and live tunnels in one cockpit, Tab between.
- feat: tunnels page shows every SSH forward with live throughput, channel events and the apps moving bytes. Local, Remote and Dynamic SOCKS.
- feat: detail panel reveals which client process owns each open channel, with a 60-second swimlane of opens and closes.
- feat: add a tunnel from the tunnels page itself, with a fuzzy host picker that filters as you type.
- change: Tab and Shift+Tab now switch between Hosts and Tunnels pages instead of cycling group tabs.
- feat: ProxyJump bastions get their own credentials.
- feat: Each hop in your jump chain reads its own keychain, 1Password, Bitwarden, pass or Vault KV entry, so multi-hop SSH connects without typing.
- feat: Every hop is scoped to its own retry window, so a stale bastion marker no longer blocks the next reconnect.
- change: Prompt-based credential lookup is restricted to the hosts in your ProxyJump chain, so a malicious server cannot phish credentials for other entries in your config.
- fix: Tighter releases. Build verification stays stable across calendar days and CI runners.
- feat: Claude Desktop one-click install with safe defaults.
- feat: Download the
.mcpbbundle from any release and double-click. Your agent getslist_hosts,get_hostandlist_containersout of the box. No shell, no container control. - feat:
purple mcp --read-onlyexposes the same safe trio when wiring up Claude Code, Cursor or any other MCP client by hand. - feat: Every MCP tool call lands in
~/.purple/mcp-audit.logas JSON. Timestamp, tool, args, outcome, reason. Owner-only file mode.run_commandarguments redacted so passwords on shell flags never hit disk. Redirect with--audit-log <PATH>or turn it off with--no-audit. - feat: Audit log refuses to open through a pre-existing symlink, so a writable-directory attacker cannot redirect writes elsewhere.
run_commandswitched off busy-polling and clamps oversized timeouts, so a runaway agent cannot pin the server. - feat: Linux musl builds for
x86_64andaarch64ship next to the existing glibc binaries. Drop the static binary on any distro and run. - change: Wordmark refreshed with cleaner box-drawing strokes. Same cadence, still a cyan period at the end.
- feat: Live progress, live hosts, untruncated IPs.
- feat: The sync footer shows which provider is in flight, how many providers are done and a running diff, so you can tell at a glance what is changing in your host list.
- feat: Online indicators pulse gently so a quick scan of the host list tells you which hosts are alive right now.
- feat: IP addresses in the address column always render in full, even next to a ProxyJump or tunnel indicator, so you can read and copy them without squinting.
- change: Welcome, Help and What's New overlays share one clean logotype with the cyan-dot accent from the landing page, giving web and TUI one consistent look.
- fix: Upgrade toasts fire reliably after a brew or curl install when the previous run was a dev build, so you actually see release notes for the version you just installed.
- feat: Cleaner internals, steadier releases.
- change: Domain types now live with the state they belong to. Screens, pickers, tags, sync records and reload tracking each move to their own module, so the next change you make lands in one obvious place.
- change: The
UiSelectiongod-struct becomes a small set of focused picker states, making overlay behaviour easier to read and extend. - change:
App::newshrinks from 124 lines to 48 by delegating to per-substate constructors that make startup initialisation explicit.
- feat: Tighter foundations for faster, safer releases.
- change: App state is split into six focused domains (hosts, tunnels, snippets, providers, forms, status) so changes land in one place and are easier to reason about.
- change: New behaviour tests cover status routing, toast expiry and provider ordering, catching regressions earlier.
- change: Fewer surprise file reads at startup. Provider state loads explicitly in one place, so tests and tools run predictably.
- feat: Confident edits on every host, shared lines included.
- feat: Multi-alias
Hostlines likeHost web-01 web-01.prodare first-class in the TUI. Edit, rename and delete them from any alias and the on-disk config keeps up. - feat: Deleting one alias from a shared line keeps the surviving aliases and their shared directives in place, ready to use.
- feat: The delete confirm dialog spells out the sibling aliases that will survive, so you press y knowing exactly what stays.
- change: Vault SSH certificates and Vault HTTP endpoints scope themselves per-alias automatically, keeping shared lines clean.
- change: OpenSSH itself is now a test oracle. Purple's parse and serialize cycle is cross-validated against
ssh -Gon 16 curated configs plus every fuzz seed, on top of 637k-run fuzzing.
- change: Codebase tune-up: sharper debug trail, snappier renders.
- change: Debug logs now show every screen navigation, so support bundles explain exactly how you got into a state
- change: Cloud sync thread-spawn failures log the underlying OS error instead of a generic "failed to start" toast
- change: Preference-save errors (view mode, sort order) now surface in the debug log instead of being silently dropped
- fix: Remove a theoretical crash path in toast-timeout calculation when a new message class is added
- change: Snappier host list. Safer, tighter releases.
- change: Large inventories render faster. Column widths and group health summaries are cached across frames instead of rebuilt on every render tick
- change: Editing the installer or landing page no longer risks breaking getpurple.sh. One command regenerates the embedded copies from source
- change: Full pre-commit suite now runs in CI. Format, clippy, build, test, deny, MSRV, doc, site sync, smoke test, design system, messages, keybindings and visual regression all gate every push
- change: Adding a new cloud provider is one entry in one table instead of edits to four parallel lookups
- fix: Update, tunnel and snippet CLI output routed through the centralized message module, keeping wording consistent
- fix: SSH prompts no longer bleed into the TUI
- fix: Opening the container overlay on an untrusted host now shows a clear "host key unknown" message instead of raw SSH prompt text leaking across the screen
- fix: Background SSH fetches (containers, file browser listings) refuse untrusted hosts cleanly. Connect once with Enter to trust a host, then the overlays work as expected
- change: Captured SSH calls no longer inherit stdin, so nothing can escape into the terminal while purple is drawing
- feat: What's New catches up even if you skipped releases
- feat: Press n on the host list or command palette to reopen the overlay
- fix: Overlay bullets render without raw markdown and wrap cleanly on narrow terminals
- fix: Version-check cache writes atomically and survives long release headlines
- fix: Picker hints now say Space, matching the key you actually press
- fix: Password Source, ProxyJump, SSH Key, Vault SSH Role and provider Regions/Endpoint fields all show the correct Space hint
- fix: Flaky preferences test race eliminated. Handler and preferences tests no longer collide
- change: Form hint copy centralized in one place so wording stays consistent across forms
- change: Docs caught up. llms.txt, landing page and wiki now say Space for picker opens
- feat: One consistent look, feel and keyboard everywhere
- feat: Enter always submits. Space activates the focused field. No more guessing which key does what
- feat: Confirm dialogs accept only y, n or Esc. Labels spell out the stakes before you commit
- feat: Toast notifications show a shrinking bar. Errors stay until acknowledged. Warnings auto-expire
- feat: Focused form fields tell you what Space does. Toggles, pickers and text fields each show their own hint
- fix: A stray keypress no longer silently triggers destructive actions. Closes #27
- fix: Closing the bulk tag editor with unsaved changes now asks before discarding them
- feat: Provider sync catches API drift before your config breaks
- fix: Security update. rustls-webpki CVE patched
- feat: All 16 providers validated against upstream OpenAPI specs on every push. See #28
- feat: Daily GitHub Actions watches 12 provider changelog pages for deprecation keywords
- fix: Flaky bulk_tag_undo test from a shared temp file path
- feat: API contract tests catch provider drift before it breaks your syncs
- feat: 32 golden fixtures cover all 16 providers and every documented endpoint
- feat: 35 integration tests run on every push to detect response structure changes early
- Fix i3D.net FlexMetal OS metadata not showing
- The FlexMetal API returns
os.slug(e.g.ubuntu-2204-lts), notos.name. Purple now readsslugfirst withnameas fallback, so OS info appears in host details and metadata
- Bulk tag editor for multi-host tagging
- Select hosts with Space (or Ctrl+Space), press t to open the bulk tag overlay. Tri-state checkboxes: [x] add to all, [ ] remove from all, [~] leave as-is. Space cycles through all three states
- Press + to add a brand-new tag. Enter applies, Esc cancels. u undoes the entire operation in one keystroke
- Plain Space now toggles host selection (Ctrl+Space still works). Esc clears the selection
- Footer shows bulk actions (t bulk tag, r run, Esc clear, ? help) when hosts are selected
- Include-file hosts are detected and skipped with a visible warning. Mixed-state rows show a "mixed" label for accessibility on NO_COLOR terminals
- Closes #15
- Smarter forms, jump host suggestions and polished overlays
- Typing a domain or IP in the Name field auto-suggests it as the Host value. Works on Tab, Down and Enter, skips when Host is already populated
- Tags in host and pattern detail panels separated by commas (
prod, web, europe) instead of spaces, so tags containing spaces aren't ambiguous - Confirmation toasts now stay visible for 4 seconds instead of 3
- ProxyJump picker promotes likely jump hosts into a Suggestions section, ranked by usage count, keyword match (
jump/bastion/gateway/proxy/gw) and shared domain suffix (#14) - Help overlay redesigned: essentials only on the host list, centered layout, clearer labels, wiki link points to the full command reference
- Host indicators stay visible when the detail panel is open
- Tunnel (⇄) and proxy jump (↗) indicators now appear next to the host name in compact view instead of disappearing with the address column. Active tunnels show in purple, configured tunnels and jumps in muted style
- Vault SSH sign dialog spacing improved. Host list is visually separated from the question and the skip note
- Vault SSH role picker and smarter defaults
- Vault SSH Role field offers a picker when roles are already configured on other hosts or providers. Press Enter to pick or type one manually (#26)
- Scheme-aware default ports for Vault address:
:443for https,:80for http,:8200for bare hostnames - Vault SSH placeholder hints explain authentication flow ("auth via vault login")
- SSH disconnect reasons shown in toast instead of just "exited with code 255". Full stderr context joined with pipe separators so you see why the connection was closed
- Vault batch signing completion status now properly clears the sticky progress footer
- Tags and alias placeholder hints clarified to avoid comma confusion
- Tag input bar shows placeholder with cursor before hint text when empty
- Updated dependencies to latest compatible versions
- Internal cleanup. Leaner App struct and event loop
- App state grouped into sub-structs: PingState, VaultState, UpdateState, TagState (#25)
- Event loop arms extracted from run_tui (1300 lines) into handler/event_loop.rs
- CLI subcommand handlers extracted from main() into cli.rs
- SshContext struct eliminates repeated function arguments across remote operations
- SnippetEvent bridge thread removed. Snippets send events directly to the main loop
- TUI smoke test: automated tmux-based test navigates all 22 screens in demo mode
- Fixed 6 flaky test races (hardcoded temp paths and global state interference)
- Fixed 9 rustdoc warnings (unclosed HTML tags and bare URLs in doc comments)
- Command palette. Press
:to search and run any action - 24 searchable actions: add, edit, delete, file explorer, tunnels, containers, SSH keys, providers and more (#21)
- Type to filter by name, press Enter to execute. Case-insensitive matching
- Up/Down to navigate, Esc to close, Backspace to clear filter
- Shortcuts shown next to each command so you learn the direct keys over time
- Footer shows
: cmdshint. Help overlay lists:in the TOOLS section
- Toast notifications for user action feedback
- Copy, sort, delete and error messages now appear as a bordered overlay box in the bottom-right corner instead of blending into the footer
- Toast queue buffers rapid actions so no feedback is lost (max 5 queued)
- Keyboard hints in the footer stay visible at all times. Status messages no longer replace the "? more" help hint
- Four message classes: Confirmation (toast, 1.5s), Info (footer, 3s), Alert (toast, 5s) and Progress (footer, sticky)
- Background events like provider sync and ping go to the footer. Direct user actions go to toast
- Debug logging for all status message routing decisions
- Debug logging for silent error paths across the codebase
- Pipe read failures in MCP tool execution, Vault SSH signing and Tailscale provider now surface in the log instead of being silently swallowed
- First-launch init (directory creation, SSH config backup, permission setting) logs warnings on failure
- Connection history read/write errors, preferences file access failures and SSH config backup pruning failures are now logged
- Thread panics in stderr capture (SSH connection) and stdout/stderr readers (snippet execution) log a warning instead of silently returning empty strings
- Tunnel and process cleanup failures (kill/wait) log at debug level
- Proxmox guest OS info and VM config API calls log the specific failure reason instead of returning None silently
- Version check cache write failures log at debug level
- Internal: extract CLI handlers from main.rs, move test modules into dedicated files across the codebase, document unsafe block invariants, replace fragile unwrap patterns with let-else guards, route TUI-context error messages through the log system instead of stderr
- Safer render paths: recover from poisoned mutex, remove unwrap panics from container overlay, replace unreachable! with safe fallbacks in provider and tunnel forms
- Faster host sorting: cache lowercased keys instead of allocating per comparison. HashSet dedup for group tab ordering
- Allocation-free host width calculation in the host list renderer
- Container cache write errors now surface in the debug log instead of being silently swallowed
- Internal: split handler.rs (11k lines) and app.rs (11k lines) into focused submodules. No behavior change
- Active tunnels now render green in the detail panel
- Tunnel rules in the detail panel TUNNELS section use a
→arrow between the local and remote endpoints, soLocalForward 8200 10.30.0.3:8200displays asL 8200 → 10.30.0.3:8200. DynamicForward entries keep their single-value form (D 1080) - Active tunnel lines use the theme success color instead of bold, matching the green convention already used for active hosts in the host list
- Askpass now works from headless ssh sessions on Linux
- Switch
SSH_ASKPASS_REQUIREfromprefertoforceon every ssh and scp launch (connect, tunnel, file browser, snippet). OpenSSH'sprefermode silently no-ops when bothDISPLAYandWAYLAND_DISPLAYare empty and falls back to the TTY prompt, which broke Bitwarden, 1Password, Vault KV, pass and keychain lookups for users running purple inside a remote shell on Arch, Hyprland and other headless Linux setups - Extract the SSH_ASKPASS env wiring into
askpass_env::configure_ssh_commandso all four call sites share one regression test that inspectsCommand::get_envs()directly. A future change back toprefernow fails CI - Resolves #19
- Tmux-aware SSH: new window instead of TUI suspend
- When purple runs inside a tmux session, pressing Enter on a host opens SSH in a new tmux window named after the alias. The purple TUI stays alive in the original window so you can switch between sessions with
prefix + n/pand keep navigating other hosts - Detection via
$TMUXenv var. No tmux means the current suspend-and-restore behavior is unchanged - Hosts with an askpass source (keychain, 1Password, Bitwarden, Vault KV, pass, cmd) keep the suspend-TUI flow because the askpass relay needs inherited stdin
- Vault SSH cert signing still runs before the tmux window opens, so short-lived certs are refreshed exactly as before. Signing status messages surface via the purple status bar
- Resolves #18
- Remove vault sign from host list footer to reduce clutter
- Structured logging to ~/.purple/purple.log
--verboseflag enables debug-level logging.PURPLE_LOGenv var for finer control (trace/debug/info/warn/error/off)purple logssubcommand:--tailto follow in real time,--clearto delete- Log entries carry fault domain prefixes:
[external]for remote/tool errors,[config]for local config issues,[purple]for internal errors - Startup banner records purple version, SSH version, terminal, providers and askpass sources for diagnostics
- Automatic log rotation at 5 MB
- HashiCorp Vault SSH certificate signing
- Short-lived SSH certificates signed via the HashiCorp Vault SSH secrets engine. Per-host role in
# purple:vault-ssh <mount>/sign/<role>, per-provider default invault_role=. Host overrides win over provider defaults Vkey bulk-signs every host needing renewal. PressVagain to cancel. Detail panel shows cert TTL under theVAULT SSHsection with a "(press V to sign)" affordance when missing, expired or invalid- Automatic renewal on connect via
ensure_vault_ssh_if_needed, so an expired cert is re-signed before the SSH session starts - Cert cache under
~/.purple/certs/<alias>-cert.pub. Background status checks with 5 minute TTL, shorter 30 second backoff on errors - Detail panel reflects external
purple vault signruns (CLI or another purple instance) within one render frame via mtime-based cache invalidation - Vault SSH address configurable per host (
# purple:vault-addr), per provider (vault_addr=) or per CLI invocation (purple vault sign --vault-addr). Purple exports the resolved value asVAULT_ADDRon thevaultsubprocess, so you no longer need to export it in every shell you launch purple from - New "Vault SSH Role" and "Vault SSH Address" fields in the host and provider forms. Progressive disclosure: Address appears when Role is set, with provider inheritance hint
- CLI:
purple vault sign <alias>andpurple vault sign --all, both accepting--vault-addr <url>. Shells out tovault write -field=signed_keyso existing Vault authentication (VAULT_TOKEN, token helpers, OIDC, etc.) applies - Bulk sign detects concurrent external
~/.ssh/configedits via mtime and merges instead of overwriting, so edits in another editor are preserved - Virtual tags
vault-ssh(any host with a resolved role) andvault-kv(any host using thevault:askpass prefix) for filtering - Distinct from the HashiCorp Vault KV secrets engine used as a password source via the
vault:askpass prefix. UI, CLI and docs keep the two engines strictly separated - Vault SSH address normalization: bare IP or hostname auto-expands to
https://IP:8200. Explicithttp://for dev-mode Vault servers - 30 second timeout on vault CLI subprocess. Previously hung indefinitely when the Vault server was unreachable
- Friendly error messages for common Vault SSH failures: connection refused, connection timed out, host not found, TLS mismatch (HTTP vs HTTPS), permission denied, token expired
- Signing progress shows animated spinner. Error messages stay visible until the next action (sticky status)
- Pre-check on
V: warns immediately when no Vault address is configured instead of failing silently after the confirm dialog - Detail panel Vault SSH section: shows role name instead of full mount path. Address moved to edit form (e) to save space
- 1000+ new tests covering the Vault SSH write paths, wildcard safety invariants (proptest across 512 random configs), Match block inertness, CRLF preservation, rollback on write failure, mtime cache staleness, subprocess env propagation and CLI flag parsing
- Fix pattern tags missing from tag grouping tabs and counts
- Fix tag picker showing (0) for tags that only exist on patterns
- Fix generic search not matching pattern tags
- Fix group-by-tag clearing when tag only exists on a pattern
- Color themes. 11 built-in themes with live preview (
mkey) - Custom themes from
~/.purple/themes/*.toml - CLI:
purple theme list,purple theme set <name>and--theme <name>session override - Pattern inheritance: ProxyJump, User and IdentityFile from pattern blocks (e.g.
Host *,Host web-*) now inherited by matching hosts. ↗ indicator and ping logic reflect inherited ProxyJump - Edit form shows inherited values as dimmed placeholders with source pattern (e.g.
gateway ← *) - Self-referencing ProxyJump loop detection: ↗ in error color, ROUTE warning in detail panel and fix hint in edit form when a pattern assigns a host as its own jump host
- Fix detail panel PATTERN MATCH section no longer shows hostname-matched patterns that SSH would not apply
- Fix error messages now show in overlay footers instead of behind dimmed background
- Fix editing multi-host patterns (e.g.
Host web-* db-*) failing with false "no longer exists" error
- Progressive disclosure in host and provider forms. Required fields shown first, arrow down reveals optional fields
- Demo mode (
purple --demo) with synthetic data for screenshots and recordings
- Animation state separated from App into dedicated AnimationState module
- Animated braille spinner for ping checking status
- New welcome screen logo (ANSI Shadow style)
- Lowercase README badges
- Record connection history when running snippets on hosts via TUI
- Fix group bar selector not following selected host in tagged view
- Tagged view group bar now shows only user tags. Provider tags no longer appear as tabs
- Cleaner host list and keycap-style footer keys
- Streamlined columns: NAME, ADDRESS, TAGS (up to 3) and LAST. Auth, tunnel and ping moved to detail panel
- ADDRESS column shows hostname:port (user moved to detail panel). Hidden when detail panel is open
- ProxyJump hosts now inherit ping status from their bastion host instead of showing "can't ping directly"
- Tags displayed without # prefix throughout the UI
- Snippet parameter form shows discard confirmation when pressing Esc with modified values
- Detail panel shows friendly password source labels (keychain, 1password, bitwarden, pass, vault) and ping RTT
- Proxmox no longer injects resource type (qemu/lxc) as provider tag. Type is already in metadata
- SSH key detail overlay now shows Esc/close footer
- Online status dots use dimmed green to distinguish from success messages
- Health summary spans (●23 ▲2 ✖1) available for group headers
- Live host health status with RTT measurement and auto-ping on startup
- Status dots before each host: ● online, ▲ slow, ✖ down, ○ unchecked (color + shape for accessibility)
- PING column shows response time (42ms, 1.2s, 10s+). Detail panel shows RTT under CONNECTION
- Slow host detection with configurable threshold (default 200ms, set slow_threshold_ms in preferences)
- Sort by health status: press s to cycle to "down first" (unreachable hosts at top)
- Down-only filter: press ! to show only unreachable hosts
- Ping results expire after 60 seconds with automatic cleanup
- Auto-ping enabled by default (disable with auto_ping=false in preferences)
- Provider sync status no longer flickers between updates
- Visual redesign with tab navigation, section cards and scoped search
- Tab/Shift+Tab cycles through provider groups or tags. Esc resets to All
- Search respects active tab: filters within the selected group only
- Tag mode in navigation bar: when grouped by tag, top tags shown as tabs
- Bordered host list and detail panel with section cards
- Status indicators per host row: reachable, unreachable, checking
- Green highlight for recent connections in Last column
- Detail panel sections as visual cards with rounded borders
- Last section stretches to fill panel height
- Pattern match sections clearly labeled
- All containers and tunnels shown (no more truncation)
- Space-separated footer (cleaner look)
- File explorer shortcut changed from f to F for consistency
- Help screen updated with Tab/Shift+Tab, scoped search, aligned columns
- Proxmox stopped VMs no longer marked stale. Stopped and no-IP VMs are included in sync with empty IP to prevent false stale detection
- Collapsible groups removed; Tab/Shift+Tab tab navigation replaces Enter-to-collapse
- Collapsible groups, Ctrl+A select all and smarter Proxmox OS detection
- Navigate to a group header and press Enter to collapse or expand it. Collapsed state is saved between sessions
- Ctrl+A to select or deselect all visible hosts. Works with search filters and collapsed groups
- Proxmox VMs with QEMU guest agent now show actual OS (e.g. "Debian GNU/Linux 13 (trixie)") instead of generic "Linux 2.6-6.x"
- Ping results no longer persist after clearing. Background ping threads are properly discarded
- Column hide priority improved: tags stay visible longest on narrow terminals
- Detail panel wider (40/46 columns) and shown by default
- Group headers are bold with collapse indicators
- Pinned "? more" help hint in footer
- Breadcrumb navigation in overlay titles (e.g. "Providers > AWS")
- Sync completion shows change summary (e.g. "+3 ~1 -2")
- Refreshed welcome screen with new logo and "Press ? anytime for help"
- Help screen shows issue tracker link
- Group hosts by any tag. Press g to cycle: ungrouped, provider or tag.
- Tag grouping opens a picker to choose which tag to group by. Thanks @AciDCooL for the feature request
- Group preference persisted across sessions and migrated automatically from the old provider-only setting
- Tag pickers close gracefully on config reload during provider sync
- Stale tag preferences cleared on startup when the tag no longer exists
- Dimmed background behind overlays for better visual depth and focus
- Form divider lines rendered dim to establish clear visual hierarchy (border > labels > dividers)
- Three-tier color support: truecolor (dark grey fg), ANSI 16 (DarkGray), NO_COLOR (DIM modifier only)
- Consistent dimming across open animation, steady-state and close animation
- Host patterns support
- Wildcard blocks like
Host *.example.comandHost 10.30.0.*now appear in a dedicated Patterns group at the bottom of the host list - Add, edit, clone and delete pattern blocks directly from the TUI (
Ato add a new pattern) - Full SSH glob matching engine:
*,?,[charset],[!charset]/[^charset], ranges,!negationand multi-pattern (space-separated) - Detail panel shows inherited directives from matching patterns for each host. Pattern detail view lists all matching hosts
- Patterns included in search, tag filtering (
tag:fuzzy andtag=exact) and tag picker - Context-aware footer: pattern-specific actions shown when a pattern is selected
- Dynamic column widths in key list and key picker overlay. Columns now adapt to content width instead of using fixed sizes
- TransIP provider. 16 cloud providers now supported
- RSA-SHA512 signed JWT authentication or pre-generated Bearer token
- Syncs VPS name, IP, availability zone, product plan, OS and status as provider metadata
- Native TransIP tags synced as provider tags
- Single API call fetches all VPS instances (no pagination needed for typical fleets)
- i3D.net provider. 15 cloud providers now supported
- Syncs both dedicated/game servers and FlexMetal on-demand bare metal in a single sync
- Static API key authentication via PRIVATE-TOKEN header
- Dedicated hosts: server category and CPU specs as provider metadata
- FlexMetal servers: location, instance type, OS and status as provider metadata. FlexMetal tags synced as provider tags
- Cursor-based pagination for dedicated hosts, offset-based for FlexMetal
- Leaseweb provider. 14 cloud providers now supported
- Syncs both dedicated (bare metal) servers and public cloud instances in a single sync
- Static API key authentication via X-Lsw-Auth header
- Dedicated servers: location, specs (CPU and RAM) and delivery status as provider metadata
- Public cloud instances: region, instance type, OS image and state as provider metadata
- Offset-based pagination for both product lines
- OVHcloud Public Cloud provider. 13 cloud providers now supported
- Custom OVH API signature authentication (SHA-1 signing with application key, secret and consumer key)
- EU, CA and US API endpoint picker (defaults to EU)
- Syncs instance name, IP, region, flavor type, OS image and status as provider metadata
- Public IPv4 preferred, falls back to public IPv6 then private IPv4. CIDR suffixes stripped automatically
- HTTPS enforced on all OVH API calls. Project ID validated before any network request
- Smooth animations for overlays, detail panel and welcome screen
- Overlay screens open and close with a zoom scale effect (150ms ease-out cubic, 350ms for welcome)
- Detail panel slides open and closes with a smooth width transition. Pressing
vmid-animation reverses direction seamlessly - Welcome screen redesigned with block-art logo (line-by-line reveal), typewriter text and larger dialog
Ctrl+Eedits the selected host directly from search mode without leaving the search (thanks @UnspecifiedId)- Form borders use purple accent color for host, provider, tunnel, snippet and parameter forms
- Animation loop runs at ~60fps during transitions, returns to blocking event wait when idle
- MCP server for AI agents
purple mcplets Claude Code, Cursor and other AI assistants list hosts, run commands and manage containers via JSON-RPC 2.0- Five MCP tools: list_hosts, get_host, run_command, list_containers and container_action
- Alias validation against SSH config before any SSH execution (prevents connections to hosts outside your config)
- SSH timeout protection on all MCP tool calls including container operations
- Container ID injection prevention via ASCII allowlist validation
- Add fuzz-equivalent property tests for SSH config parser
- Arbitrary Unicode and raw byte inputs now verify idempotency and mutation safety (delete, undo, update, swap, add) in CI
- Fix Oracle Cloud group header cleanup. Orphaned headers were not removed when all Oracle hosts disappeared
- Shell-escape alias and hostname in custom askpass commands to prevent metacharacter injection
- Strip control characters from provider config values to prevent INI format corruption
- Terminal cleanup on TUI init failure. Raw mode and alternate screen are now restored if cursor hide or clear fails
- Safe PID conversion in snippet process guard
- Deduplicate percent-encoding and date formatting across provider modules
- Cache clipboard command detection to avoid repeated subprocess spawns
- URL-encode Vultr pagination cursor in query parameters
- Replace tautological connection tests with real integration tests
- Oracle Cloud Infrastructure (OCI) provider. Sync Compute instances via OCI REST API with RSA-SHA256 request signing
- Multi-region support with TUI region picker (38 regions across Americas, EMEA and Asia Pacific)
- Recursive compartment sync. Point at a tenancy or compartment OCID and all sub-compartments are included
- Authenticate with your existing OCI config file (~/.oci/config). No extra credentials to manage
- Metadata: region, shape, os and status shown in detail panel. Freeform tags synced as provider tags
- Help overlay layout refined. Narrower width, rebalanced columns and tighter key alignment
- Region picker spacing fix in provider form
- Context-sensitive help. Press
?on any screen to see its shortcuts - Help works in host list, file browser, snippets, containers, tunnels, providers, SSH keys, tag picker and host detail
- Improved visual hierarchy. Section headers are bold, descriptions are dim, keys are right-aligned
- Host list help reorganized into task-based groups: Navigate, View, Forms, Manage Hosts, Connect and Run, Tools
- Smaller help overlays for sub-screens. No duplicate headers, compact sizing
- Missing shortcuts added across all screens (q/Esc, PgDn/PgUp, j/k)
- Help accessible through confirmation guards and search mode
- Container management over SSH. Works with Docker and Podman
- Press
Con any host to see all containers. Start, stop and restart without leaving purple - Auto-detects Docker or Podman on the remote host. No agent. No web UI. No extra ports
- Cached container data shown in the detail panel after first fetch
- Consistent footer spacing across all overlay screens
- Spacer row between content and footer in all overlay screens for cleaner visual separation
- Startup sort now selects the first host in sorted order instead of the first host in config order
- Rebranded from "SSH config manager" to "terminal SSH client" across all user-facing text
- 1500+ new parser robustness tests covering malformed input, quoting edge cases, Match blocks and mutation sequences (4200+ total)
- Soft-delete for disappeared provider hosts
- Hosts that vanish from cloud sync are marked stale instead of silently kept or hard-deleted. Stale hosts appear dimmed in the host list and sort to the bottom
- Purge stale hosts with X. Confirmation dialog shows host names (up to 6) before deletion
- Per-provider purge from the provider list (X key scoped to the selected provider)
- Provider list shows per-provider stale count in red with X key hint in footer
- Detail panel shows "Stale" field with relative timestamp in red
- Virtual "stale" tag for filtering (tag:stale fuzzy, tag=stale exact, appears in tag picker)
- Stale connection warning on Enter, edit, delete, clone, tunnels, snippets and file browser
- Editing a stale host clears the stale marker on save
- Stale hosts automatically un-stale when they reappear in the next provider sync (including stopped VMs with empty IP)
- Partial sync failures suppress stale marking to prevent false positives
- Active tunnels cleaned up on purge (after successful config write)
- CLI:
purple syncprints "Marked N stale." per provider - Footer separators between every action (consistency fix across all screens)
- Delete confirmation dialog widened to 52 columns (consistent with other dialogs)
- Detail panel route visualization uses display width instead of byte length for Unicode correctness
- Fix missing blank line when adding a provider host before another provider's group header
- 143 new tests covering stale marking, clearing, purge, sort, filter, config integrity and round-trip fidelity (4111 total)
- Sparkline now shows your full connection history
- Fix timestamp retention to match sparkline range. History now keeps 365 days instead of 90 so the auto-scaling sparkline can show up to 1 year of connection activity
- Smarter forms, visual routes and a sparkline that fits your data
- ProxyJump chain visualization in detail panel. Shows the full hop route (○ you → ● bastion → ● target) with validation for missing hosts in red
- ProxyJump arrow indicator (→) in host list for hosts using a jump host
- Activity sparkline auto-scales to your data. Ranges from 5 days to 1 year based on connection history
- Sparkline shows dotted baseline (·) for empty periods and a midpoint time label for orientation
- Fewer than 3 connections show a compact text list instead of a sparkline
- Dirty-check on Esc. All four form types now ask "Discard changes?" when you press Esc with unsaved edits
- Auto-submit after picker selection. Pick a key, proxy host or password source and the form submits if ready
- Space bar toggles and cycles. Tunnel type and provider booleans now use Space instead of arrow keys
- Arrow keys are cursor-only in all forms. Left/Right never toggle or cycle values
- HostDetail overlay is no longer a dead end. Press e to edit, T for tunnels, r for snippets
- Signal safety during SSH. Ctrl+C reaches SSH normally but no longer kills purple
- Tunnel processes run in their own process group for clean signal isolation
- Context-aware mode badges in title bar (TAGGING, N SELECTED)
- Search footer shows tag syntax hints (tag: fuzzy, tag= exact) and improved match count (N of M)
- Import confirmation accepts both y and Y
- Consistent footer separators (│) across all screens with shared helper functions
- Help screen updated with Space toggle, detail panel scroll, snippet output navigation and smart-paste hint
- Smart-paste placeholder in Alias field shows user@host:port format
- Edit form title shows the host alias being edited
- 62 new tests covering dirty-check, delete confirmations, navigation, ProxyJump chain resolution and sparkline behavior (3968 total)
- Redesigned host list with smarter column layout and provider tag separation
- Provider tags are now stored in a dedicated comment and always mirror the remote. Your own tags are never touched by sync
- Two-cluster column system. Left cluster (name and host) and right cluster (auth, tags, last) separated by a flexible gap
- Add header underline and bold column headers for better scannability
- Add sort indicator next to the active sort column name
- Add selection indicator on the left edge of the selected row
- Show dash for empty auth and last cells instead of blank space
- Show read-only provider tags in the tag edit bar
- Group headers show a horizontal leader line after the label
- Tighter column gaps (2-3 fixed) for a more compact and professional look
- Shorten time labels in the last column (5m instead of 5m ago)
- Sanitize tag values: strip control characters, commas, bidi overrides and enforce max length
- Remove --reset-tags CLI flag (no longer needed)
- Add CI workflow with format, clippy, test, cargo-deny and MSRV checks
- Fix parser handling of lone \r line endings breaking round-trip idempotency
- Add property-based and fuzz testing for SSH config parser
- Add Dependabot for weekly cargo and GitHub Actions updates
- Add cargo-deny for license and vulnerability scanning
- Update GitHub Actions to latest versions (checkout v6, upload-artifact v7, download-artifact v8)
- Update rustls-webpki to 0.103.10 (security fix)
- Welcome screen shows host count and offers known_hosts import on first launch
- Import hosts from ~/.ssh/known_hosts with I key
- Detail panel tags wrap across multiple lines to fit panel width
- Update badge headline truncates with ellipsis instead of being clipped
- Provider metadata uses provider-specific terminology (instance, vm_size, zone, location, image, specs)
- Improved SSH config compatibility: UTF-8 BOM, Host= syntax, ${VAR} in includes, quoted paths, depth 16
- Automatic repair of absorbed group comments and orphaned group headers
- Synced hosts insert adjacent to existing provider group for consistent grouping
- Multi-level undo for host deletion (up to 50 levels)
- Welcome screen with one-time backup of original SSH config to ~/.purple/config.original
- Advisory file locking prevents concurrent write corruption
- New hosts insert before trailing Host * blocks to preserve SSH first-match-wins ordering
- Inline comments preserved when updating directives
- UpCloud boot disk preferred over first storage device for image metadata
- Scaleway pagination via response body instead of X-Total-Count header
- Proxmox QEMU OS type labels match qm.conf(5) manpage
- Atomic writes call fsync before rename and clean up temp files on failure
- Added release notes to update flow and GitHub releases
- TUI update badge shows changelog headline from GitHub release body
- Full release notes displayed after
purple updatewith markdown stripping - Release workflow extracts changelog section as GitHub release body
- Added CHANGELOG.md with full release history
- Improved Hetzner location migration and GCP zones/IPv6 support
- Added provider metadata (region, plan, os, status) to sync and detail panel
- Added Tailscale to provider badges on landing pages
- Added Tailscale provider with local CLI and HTTP API support
- Added Linux support for pre-built binaries, installer and self-update
- Improved snippet picker: column headers, aligned layout, allow spaces in names, rename raw to terminal
- Added in-TUI snippet output, parameterized snippets, snippet search, parallel execution and terminal fallback
- Fixed status message leaking into overlay footers
- Added file browser sort directions and sync history persistence
- Improved footer and help overlays
- Fixed symlink handling in file browser
- Rewritten product messaging for TUI-first positioning
- Fixed Include equals-sign parsing, stale multi-select, tag input cursor and sort selection persistence
- Added remote file explorer with scp transfer
- Fixed 9 bugs found during code review
- Redesigned help overlay with two-column layout
- Added getpurple.sh label to host list
- Added Azure cloud provider sync
- Added GCP Compute Engine cloud provider sync
- Dimmed group headers in host list for better visual hierarchy
- Redesigned host list with composite host column, purple accent theme and active tunnel visibility
- Fixed UI/UX consistency across footers, forms, lists and delete confirmations
- Added Scaleway cloud provider sync
- Added AWS EC2 cloud provider sync
- Fixed keychain migration safety on alias rename
- Added activity sparkline, history timestamps and detail scroll
- Improved form clarity and performance
- Stream snippet output in real-time instead of buffering
- Added full provider metadata and volatile sync
- Improved UI consistency and help attribution
- Added provider metadata sync with detail panel display
- Added command snippets with multi-host execution
- Added ProxyJump picker to host form
- Redesigned UI with rounded borders, column layout and compact forms
- Added split-pane detail panel with v key toggle
- Detect changed host keys and offer to remove old key and reconnect
- Fixed ping indicator colored space on selection
- Preserved host selection after SSH
- Fixed Left/Right toggle for VerifyTls and AutoSync fields
- Added cursor navigation in forms
- Fixed tests overwriting ~/.purple/providers
- Preserved selection after host edit
- Added SSH password management (keychain, 1Password, Bitwarden, pass, Vault)
- Hardened Proxmox provider deserialization
- Added --auto-sync/--no-auto-sync CLI flags
- Added Proxmox VE provider
- Added per-provider auto_sync toggle
- Fixed self-update failing on GitHub redirect
- Sort provider list by last sync
- Show footer shortcuts with status on all screens
- Fixed redirect following, key_detail height, width-aware truncate, deduplicate providers, validate parse_target
- Fixed missing space before update notification in title bar
- Added sync history in provider list
- Fixed tag selection reset, merged sync tags
- Added --reset-tags flag
- Added self-update and TUI version check
- Added getpurple.sh landing page, install script and Bunny edge worker
- Added tunnel management
- Fixed sync write-failure rollback, cancel-flag replacement, provider config dedup, scoped IPv6 detection
- Fixed alias_prefix validation, sync rename stability, tag-edit reload guard, equals-syntax preservation
- Added sync cancellation, token env var and atomic_write extraction
- Added group-by-provider and form conflict detection
- Hardened parser and improved sync
- Added UpCloud provider
- Fixed provider CLI config dependency, known_hosts port validation, hex hostname skip, import duplicate counter, token masking UTF-8 panic
- Added cloud provider sync (DigitalOcean, Vultr, Linode, Hetzner)
- Fixed parser = splitting, shell-quote clipboard, throttle ping-all, quote-aware comments, import reporting, symlink writer, auto-reload guard
- Fixed ping dual-stack, event thread hang, known_hosts parser, add-host rollback
- Fixed known_hosts wildcard import
- Preserved inline comments on edit
- Fixed alias whitespace validation, tab multi-pattern filtering, edit tag rollback, import group headers, included file trailing comments
- Added tags to form
- Fixed Include-in-block parsing, inline comments, wildcard validation, search restore and rollback formatting
- Fixed broken undo, write-failure rollback, include dir reload, CLI alias validation
- Fixed Unicode panic, tab parsing, CRLF preservation, include reload, import errors
- Fixed stale edit index, clipboard exit check, search ping guard, known_hosts markers, IPv6 validation
- Fixed DNS timeout, undo-on-reload, raw mode guard, deterministic history
- Fixed zombie processes, stale delete index, UTF-8 panics, Unicode width, key casing, permission races, panic hook ordering, IPv6 parsing
- Columnar layout, key picker comments, simpler keybindings
- Added tag picker, search-by-tag and key list improvements
- Monochrome theme with purple brand badge
- Most recent sort mode and purple accent colors
- Reverted Magenta borders, fixed title text readability
- Added sort mode persistence and Magenta borders
- Fixed brand badge readability across terminal themes
- Brand badge title and lowercase branding
- Design, UX and accessibility improvements
- Fixed round-trip formatting: Include parsing, indentation, blank lines, tags and swap
- Fixed SSH connection delay, terminal robustness and atomic write improvements
- Added clone, sort, tags, import, inspect, export, undo, auto-reload and connection history
- Fixed zombie processes in clipboard detection, search position restore, ProxyJump ping, Linux clipboard support
- Added search, ping, grouping, clipboard, quick-add, Include support and shell completions
- Added SSH key management (key list, key detail, key picker)
- Initial release