AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
SSH·mosh·시리얼·telnet을 하나의 로컬 라이브러리로 제공, MultiExec 안전 UX·SFTP·컨테이너·Kubernetes 지원
SSH, mosh, serial, and telnet sessions in one local-first library, with MultiExec safety UX, SFTP, containers, and Kubernetes.
개발 도구Swift · ShellGitHub @mcglothi온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
A fast, beautiful, native macOS workbench for people who live on SSH.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A fast, native macOS workbench for people who live in remote terminals.
Portside is a session manager and terminal for operators who run fleets of
Linux servers — plus their containers, Kubernetes pods, serial consoles, and
legacy telnet endpoints — from a Mac. Connect over OpenSSH or mosh, plug into a
switch with a native serial bridge, and keep every target in one searchable,
foldered library. Multi-host broadcast with guardrails, SFTP, port forwarding,
and credential glue all live in the same native window.README 전문 보기 ↗A fast, native macOS workbench for people who live in remote terminals.
Portside is a session manager and terminal for operators who run fleets of Linux servers — plus their containers, Kubernetes pods, serial consoles, and legacy telnet endpoints — from a Mac. Connect over OpenSSH or mosh, plug into a switch with a native serial bridge, and keep every target in one searchable, foldered library. Multi-host broadcast with guardrails, SFTP, port forwarding, and credential glue all live in the same native window. No Electron, no web view: SwiftUI and a real terminal, built around the tools you already use.
Early days, moving fast. Built on the coast of Maine. ⛵
Grab the latest notarized build from Releases, or:
brew install mcglothi/tap/portside
Builds are Developer ID signed and notarized by Apple, and keep themselves current via Sparkle. Requires macOS 14+ on Apple silicon — Intel Macs aren't supported. If that matters to you, please open an issue.
One foldered library for SSH and mosh hosts, containers, Kubernetes pods, serial consoles, and telnet endpoints — with transport and environment badges.
⌘K Quick Connect fuzzy-searches every saved target and recent connection at once.
Real terminal tabs over the OpenSSH you already have configured — keys, agent, and ProxyJump chains included.
MultiExec broadcasts your keystrokes to every included pane — with a loud banner counting what's live. Drop a host out for a single command and put it back (⌥⌘M, or the status bar under any pane) without disarming.
The SFTP browser rides the same SSH connection as your shell — no second login — with drag-and-drop transfer right beside the terminal.
macOS has excellent terminal emulators — iTerm2 and WezTerm are superb. What it lacks is a native operator workflow: a session library you can organize, broadcast execution across a fleet with real safety UX, credential glue, file transfer, and container/Kubernetes access — in one fast surface. Portside exists to fill that gap without giving up native speed and macOS polish.
Opinionated bets:
~/.ssh/config, agent,
keys, and ProxyJump chains work on day one, unmodified.prod, nonprod,
personal, nested as deep as you like. Everything is editable in place.kubectl or oc (NKP,
GKE, OpenShift, any kubeconfig, including a per-cluster file), the same way
you save a host. It runs on this Mac or through an SSH jump host, and shows
up in the library, Quick Connect, and recents like everything else. Browse
contexts, workloads (deploy/web survives rollouts), pods and containers
from the editor so you never have to remember a churning name. When a
cluster sign-in has expired, the session says so and offers the platform's
own Sign In — Portside never holds a token.~/.ssh/config import — seeds the library on first launch (follows
Include directives); re-import merges new hosts anytime..mxtsessions / .mxtmacros files
with their folder structure intact. (Macros imported before 0.17 could pick up
literal key names — yumSPACEupdate — from MobaXterm's keystroke format.
Scripts/repair_moba_macros.py fixes those in place; re-importing does not,
since import skips macros whose name already exists.)imgcat a screenshot, a Grafana export, or a plot from a
remote host and look at it where you are, instead of copying it back first.
Sixel, iTerm2 (OSC 1337) and Kitty graphics all render; the
has the details. Try it without
installing anything: .✅ Configurable scrollback, GPU (Metal) rendering, a tested terminal-compatibility matrix, native sidebar multi-selection with drag-to-folder, session restore, and split panes.
✅ Tab bar polish — keyboard tab switching (⌘⇧[/], ⌘1–9, and a ⌘←/⌘→ alias), pane zoom (⌘⇧↵), reconnect-in-place from the "session ended" bar, a tab context menu (rename / duplicate / close / close others), overflow chevrons, and a configurable MultiExec alert color.
✅ Fully remappable keyboard shortcuts, cursor shape/blink, right-click terminal copy/paste, the searchable welcome/start-page tab, app-wide and bulk password handling, and configurable auto-update checking.
✅ SFTP browser polish — auto-refresh on host switch, delete confirmation,
a persistent drag/drop hint, and cd-following with one-click shell
integration install + shell auto-detection (bash/zsh). Plus MultiExec
arming in one step, a Grid View restore bugfix, working toolbar tooltips,
an optional auto-accept-new-host-keys toggle, arrow-key navigation in both
the welcome-screen search and the sidebar filter, and single-keystroke
session reconnect.
✅ Named credential profiles — multiple reusable identities (username + SSH key and/or password), managed in Settings ▸ Profiles and applied in bulk to a multi-selection or a folder, so a fleet split across a handful of shared accounts (AD, Ansible/Nutanix service accounts, IPMI/vendor consoles, etc.) doesn't need per-host credential entry. A host holds a live reference to its assigned profile rather than a one-time copy, so rotating a profile's password or key updates every host using it immediately. The old single default password folds into this as the first profile ("Default").
✅ Pinned favorites on the welcome/start page, shown alongside "Jump back in" — hidden while actively searching, same as recents. Pin from a sidebar right-click (single host or a multi-selection), a hover star icon on each sidebar row, or a Favorite toggle in the session editor.
✅ App appearance (light / dark / follow system), independent of the terminal's color theme; favourite macros pinned to the MultiExec bar; browsable recently-closed tabs; ⌘W closes the tab; a "never connected" coverage category; and inline images documented at last — Sixel, iTerm2 and Kitty graphics all render.
✅ Host-to-host file copy — drag a file from the SFTP browser onto a different pane and it lands on that host, in whatever directory that pane's shell is currently sitting in. Drop it on a pane that is broadcasting and it goes to every host in the MultiExec group at once; files dragged in from Finder follow the same rule. The bytes relay through a staging file on the Mac (there is no safe direct host-to-host path without trusting one box with credentials for another), downloaded once no matter how many hosts receive it, and uploaded to several at a time — configurable in Settings ▸ Connection.
-CC) integration — native splits backed by a durable
remote tmux sessionRequires the Swift 6 toolchain (Xcode Command Line Tools are enough). The
package itself is still on swift-tools-version: 5.9 and builds in Swift 5
language mode — the Swift 6 concurrency migration hasn't happened yet. CI
holds the line with a per-file ratchet
(Scripts/strict-concurrency-check.sh) so the outstanding warning count can
shrink but never grow:
# Run for development
swift run
# Run against a throwaway library instead of your real one
PORTSIDE_LIBRARY_DIR=/tmp/portside-dev swift run
# Build a standalone Portside.app
Scripts/make_app.sh
open build/Portside.app
swift run otherwise shares everything with the installed app — the same
hosts, the same saved workspace, the same history — so a dev build is a small
risk to real data every time, and each launch stops to ask whether to restore
the session you left open in the other copy. PORTSIDE_LIBRARY_DIR points
it somewhere disposable instead; seeding from ~/.ssh/config is off in that
mode, so the library starts genuinely empty and your real hostnames stay out
of any screenshots.
A swift run build also has no Info.plist, so it has no Sparkle feed and
deliberately doesn't start the updater — no "couldn't check for updates"
dialog on launch, and "Check for Updates…" disables itself. Packaged builds
are unaffected: Scripts/make_app.sh writes the feed URL and public key.
Pre-1.0 and evolving quickly; expect sharp edges. Issues and ideas welcome — especially from fellow operators who live in the terminal.
cat docs/demo/portside-logo.six/dev/cu.* devices
without spawning screen. Choose baud rate, data bits, parity, stop bits,
and flow control; logging, run-on-connect, and MultiExec work on the same path.env:prod, kind:k8s,
folder:lab, profile:none, is:fav, - to exclude and /regex/; the
? beside the field lists them all, typing env: suggests values,
non-matching hosts dim rather than vanish, and filters can be saved.ssh:// and portside://connect/<name> links — open hosts from a wiki,
dashboard or script. Unknown hosts always ask first; Settings ▸ Connection can
make Portside the default ssh:// handler.cd in the live shell for bash/zsh (via the OSC 7 "current directory"
escape sequence) — one-click "Install Shell Integration" appends the
needed one-liner to the host's .bashrc/.zshrc over ssh (idempotent,
with an option to source it into the session immediately), and
auto-detects which shell you're running so you don't have to know.~/.ssh/config until a host sets it. X11 is
trusted (-Y) or untrusted (-X) per host, and needs XQuartz
(brew install --cask xquartz); hosts with X11 on say so if it's missing or
not running.-L / -R / SOCKS tunnels with live status,
start/stop, and launch-at-startup, tunneled through any host in the library.
Best-effort by design: the status tracks the ssh process, not whether
traffic still flows, and nothing restarts a tunnel that dies. See
docs/port-forwarding.md — worth two minutes before
you depend on one.R) from its "session ended" bar.✅ Changelog on update — the Sparkle update prompt now shows a cumulative changelog covering everything since whatever version you're updating from, not just the latest release's own notes, since releases ship fast enough that auto-updaters often jump several versions at once.
✅ Agent Access — Claude Code, Codex or your own scripts can list hosts,
open sessions, and (with a second switch) type into and read them, through
the portside command or as MCP tools (portside mcp). Every program is
approved by name; protected hosts and multi-line input ask every time;
commands are staged for you to run unless the agent is told otherwise; an
agent never arms MultiExec or types at a password prompt. Optional, scoped
"Don't Ask" mode for trusted setups. See docs/agent-api.md.
✅ Shared inventory — subscribe to a team's hosts, and the containers
on them, in a git repo, shown read-only beside your own, with your own
settings layered on top. Plain
git, fast-forward only, manifest sanitized. See
docs/shared-inventory.md.