{"slug": "show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts", "title": "Show HN: Shellink – let AI agents run commands on servers behind jump hosts", "summary": "Shellink, an open-source session middleware for AI agents and humans working with SSH and local terminal sessions, provides a stable CLI for connection profiles, interactive sessions, command execution, file transfer, remote editing, and session state. The tool, available on GitHub, includes a local daemon that owns sessions and exposes a Web UI plus HTTP and WebSocket APIs, designed to let AI agents run commands on servers behind jump hosts while supporting multi-hop login automation, PTY-based continuity, human supervision, and auditable operations.", "body_md": "**One stable CLI and daemon for SSH, local PTY sessions, file transfer, and remote editing — built for AI agents and humans alike.**\n\n[Features](#features) ·\n[Quick Start](#quick-start) ·\n[Documentation](#table-of-contents) ·\n[Contributing](#contributing) ·\n[中文文档](/jie123108/Shellink/blob/main/README.zh-CN.md)\n\n*An AI agent hops through a jump host and runs commands on the target server — driven entirely through the Shellink CLI.*\n\nShellink is an open-source session middleware for AI agents and humans working with SSH and local terminal sessions. It provides one stable CLI for connection profiles, interactive sessions, command execution, file transfer, remote editing, and session state. A local daemon owns the sessions and exposes a browser-friendly Web UI plus HTTP and WebSocket compatibility APIs.\n\nRepository: [https://github.com/jie123108/Shellink](https://github.com/jie123108/Shellink)\n\nSecurity warning:`command`\n\nprofiles execute their configured command as the server process user. Run Shellink only in a trusted environment and protect`SHELLINK_TOKEN`\n\n. Shellink also lets an AI agent connect directly to production servers; this carries real operational risk, so prefer read-only, inspection, or analysis operations, or point the agent at non-production environments.\n\n[Shellink](#shellink)\n\nWeb UI dashboard (session list):\n\nWeb UI live session terminal (xterm.js), including a jump-host hop:\n\nCLI/TUI session view (`shellink cli`\n\n):\n\n**SSH and custom command sessions:** Connect directly with SSH, or run a command/script inside a PTY.**Multi-hop login automation:**`connectType: \"command\"`\n\nsupports`expect`\n\nand similar scripts for multi-level bastion hosts, jump-host menus, OTP prompts, and legacy authentication flows.**Command execution and state handling:** Execute commands, inspect state, provide interactive input, and wait for the session to become ready before the next operation.**File transfer across jump hosts:** Upload and download files through the existing PTY instead of requiring SFTP. This keeps transfers working through custom command chains and multi-hop connections.**Remote file editing:** Apply precise replacements with`shellink session edit`\n\n.**Audit history and supervision:** Session input/output is retained as history for audit and replay, while`MANUAL`\n\nmode lets a human take control and supervise or answer prompts.**CLI/TUI, Web UI, REST, and WebSocket:** Use the interface that fits the workflow, with stable`--json`\n\noutput for automation.**Encrypted profiles and optional single-file binaries:** Credentials are protected in SQLite, and Bun builds are available for macOS and Linux.\n\nShellink is designed around the situations where an AI agent needs reliable access but should not guess or bypass human controls:\n\n**Scriptable multi-hop access:** Agents can reuse`expect`\n\nor other custom login scripts for several bastion hops instead of implementing each site's authentication flow themselves.**PTY-based continuity:** Commands and file transfers use the same PTY path, so an agent can work through jump hosts even when no direct SFTP or SSH endpoint is available.**Human supervision:**`AUTO`\n\nmode is for agent actions;`MANUAL`\n\nmode hands the terminal to a person for approval, OTP entry, or intervention before automation continues.**Auditable operations:** Session input/output history and daemon logs give operators a record for reviewing what the agent saw and did.**Observable progress:** Explicit session states and machine-readable CLI output let an agent decide whether to execute, send input, wait, or ask for human help.\n\nThe repository is an npm workspace monorepo with one additional non-workspace directory for agent skills:\n\n| Path | Type | Responsibility |\n|---|---|---|\n`protocol/` |\nnpm workspace | Versioned RPC methods, MessagePack frames, and Zod schemas |\n`cli/` |\nnpm workspace | `shellink` CLI, daemon lifecycle commands, and terminal UI |\n`server/` |\nnpm workspace | Unix-socket daemon, session engine, services, HTTP, and WebSocket gateway |\n`web/` |\nnpm workspace | Vue 3 browser console with xterm.js |\n`skills/` |\nplain directory | Agent skills for remote operations and iTerm2 profile import |\n\nThe runtime flow is:\n\n``` php\nflowchart LR\n  Client[\"CLI / TUI\"] -->|Unix socket, MessagePack RPC| Daemon[\"Daemon services\"]\n  Daemon --> Sessions[\"SSH / local PTY sessions\"]\n  Daemon --> Storage[\"SQLite state and encrypted credentials\"]\n  Daemon --> Gateway[\"HTTP REST / WebSocket gateway / Web UI\"]\n```\n\nThe Unix socket is the primary local interface. HTTP, WebSocket, and the Web UI are compatibility and browser layers. New local automation should use the CLI rather than implementing the socket protocol directly.\n\n**Runtime:** Node.js`>=22.19.0`\n\n; Bun is optional for compiled binaries.**Language:** TypeScript with npm workspaces.**Server:** Fastify,`ssh2`\n\n,`node-pty`\n\n,`ws`\n\n, SQLite via`better-sqlite3`\n\nand Drizzle ORM.**Protocol:** MessagePack framing and Zod validation.**Web:** Vue 3, Vite, Naive UI, Pinia, and xterm.js.**Testing:** Vitest with V8 coverage and Docker-backed end-to-end fixtures.\n\nUsing an AI coding agent?Paste this prompt into your agent's chat:\n\n```\nPlease help me install Shellink and its skills by following https://raw.githubusercontent.com/jie123108/Shellink/main/AGENTS_INSTALL.md\n```\n\nPrebuilt binaries are published for macOS and Linux (`darwin-arm64`\n\n, `darwin-x64`\n\n, `linux-arm64`\n\n, `linux-x64`\n\n). Windows is not supported; build from source instead (see below).\n\n```\ncurl -fsSL https://raw.githubusercontent.com/jie123108/Shellink/main/install.sh -o /tmp/shellink-install.sh\ncat /tmp/shellink-install.sh\nsh /tmp/shellink-install.sh\n```\n\nPin a release tag if needed:\n\n```\ncurl -fsSL https://raw.githubusercontent.com/jie123108/Shellink/main/install.sh -o /tmp/shellink-install.sh\ncat /tmp/shellink-install.sh\nsh /tmp/shellink-install.sh --version v0.1.0\n```\n\nFor a system-wide install into `/usr/local/bin`\n\n(already on `PATH`\n\non most systems), run with `sudo`\n\n:\n\n```\nsudo sh /tmp/shellink-install.sh --dir /usr/local/bin\n```\n\nThe script downloads the matching asset from GitHub Releases, verifies `SHA256SUMS.txt`\n\n, and installs `shellink`\n\nto `$HOME/.local/bin`\n\nby default. If that directory is not on `PATH`\n\n, the installer appends an `export PATH=...`\n\nline to your shell profile (`~/.zshrc`\n\n, `~/.bashrc`\n\n, etc.). Open a new shell (or re-export `PATH`\n\n), then verify:\n\n```\nshellink -V\n```\n\nRequirements:\n\n- Node.js 22.19 or newer.\n- npm.\n- Docker, only if you want to run the Docker-backed end-to-end tests.\n- Bun, only if you want to build a standalone binary.\n\n```\ngit clone https://github.com/jie123108/Shellink.git\ncd Shellink\nnpm install\nnpm run build\n```\n\nThe built CLI is available at `./node_modules/.bin/shellink`\n\n. To build a standalone executable for the current platform:\n\n```\nnpm run build:binary\nmkdir -p \"$HOME/.local/bin\"\ncp dist/shellink \"$HOME/.local/bin/shellink\"\nexport PATH=\"$HOME/.local/bin:$PATH\"\n```\n\nCross-build scripts are available for `macos-arm64`\n\n, `macos-x64`\n\n, `linux-arm64`\n\n, and `linux-x64`\n\n.\n\nStart the interactive terminal UI. It starts the user-level daemon automatically when necessary:\n\n```\nshellink cli\n```\n\nCheck the daemon and print the machine-readable agent reference:\n\n```\nshellink server status --json\nshellink agent-doc\n```\n\nCreate a command profile and session without putting credentials in shell history:\n\n```\nshellink profile create --input - --json <<'JSON'\n{\"name\":\"local-shell\",\"connectType\":\"command\",\"command\":\"/bin/sh\"}\nJSON\n\nshellink profile list --query local --json\nshellink session create --profile <profile-id> --json\nshellink session exec <session-id> --command 'uname -a' --json\nshellink session close <session-id> --json\n```\n\nFor SSH profiles, pass passwords, passphrases, and private keys through `--input FILE`\n\nor stdin. Never put them in command-line arguments.\n\nWhen running from source, `npm run dev`\n\nstarts the server and Vite development UI. Open `http://localhost:5173`\n\n. A built daemon serves the embedded UI at `http://127.0.0.1:7070/shellink/ui/`\n\nby default; the exact URL is shown by `shellink server run`\n\nor `shellink server status --json`\n\n.\n\nCustom command profiles are intended for connections that cannot be represented by a single direct SSH login. Set `connectType`\n\nto `command`\n\nand provide any command available on the server host, for example:\n\n```\n{\n  \"name\": \"Bastion menu\",\n  \"connectType\": \"command\",\n  \"command\": \"expect /opt/shellink/login-through-bastion.exp\"\n}\n```\n\nShellink starts the command in a PTY and exposes the same command, input, history, file-transfer, and editing APIs used by SSH sessions. An `expect`\n\nscript can therefore drive several bastion hosts and authentication steps as one Shellink session. The script, its dependencies, and its credentials run on the server host as the daemon user; only execute trusted commands.\n\nNote:Shellink itself does not handle a host's automatic login process. For automated login (multi-hop hops, jump-host menus, OTP prompts, and other interactive authentication flows), use an[script driven by a]`expect`\n\n`command`\n\nprofile. Other tools such as`sshpass`\n\n(password-only logins) or`ssh`\n\nwith key-based authentication and`ProxyJump`\n\n/`ProxyCommand`\n\ncan also work, depending on your environment.\n\nThe `shellink`\n\nexecutable is the client. TUI commands and resource commands (`profile`\n\n, `session`\n\n, and `webhook`\n\n) connect to the local daemon through a Unix socket. If the socket is unavailable, the client starts a detached daemon, waits for it to become ready, and then sends the request. Add `--json`\n\nfor stable, one-line machine-readable output.\n\n```\nshellink server start                 # Start in the background\nshellink server status --json         # Inspect health and active sessions\nshellink server logs --lines 100      # Read recent daemon logs\nshellink server restart               # Restart the daemon\nshellink server stop                  # Stop the daemon\nshellink server run                   # Run in the foreground\n```\n\n`server run`\n\nis suitable for development or a process manager. The daemon always starts its Unix socket. HTTP/WebSocket support is enabled by default and can be disabled with `SHELLINK_HTTP_ENABLED=false`\n\n. HTTP binds to `127.0.0.1`\n\nby default; set `SHELLINK_HOST=0.0.0.0`\n\nonly when remote access is intentional.\n\nLocal requests from `localhost`\n\nor `127.0.0.1`\n\ncan omit authentication, including permanent session-record deletes. Remote HTTP and WebSocket requests require `Authorization: Bearer <SHELLINK_TOKEN>`\n\n(or the WebSocket token query parameter used by existing clients). The Web UI probes `GET /shellink/api/auth/sensitive-ops`\n\nto decide whether a token is required for delete/purge actions.\n\nWhen nginx (or another reverse proxy) sits in front, the backend usually sees a loopback TCP peer but a public `Host`\n\nheader. That is treated as remote access: sensitive ops still require a token. `X-Forwarded-For`\n\n/ `X-Real-IP`\n\nare not trusted for the local bypass.\n\nAll HTTP, WebSocket, and Web UI routes are served under the `/shellink`\n\nprefix:\n\n| Path | Description |\n|---|---|\n`/shellink/ui/` |\nEmbedded Web UI (browser console) |\n`/shellink/api/*` |\nREST compatibility API (profiles, sessions, webhooks, auth) |\n`/shellink/ws/sessions/{id}` |\nPer-session terminal WebSocket stream |\n`/shellink/ws/events` |\nGlobal session-state event WebSocket stream |\n`/shellink/agent.md` , `/shellink/llms.txt` |\nMachine-readable agent reference (same content as `shellink agent-doc` ) |\n`/shellink/healthz` |\nLiveness probe |\n\nUse the installed reference before integrating:\n\n```\nshellink agent-doc\n```\n\nThe recommended flow is to search profiles, create a session, wait for `WAITING_INPUT`\n\n, execute commands, inspect history when needed, and close the session. Session states are `CONNECTING`\n\n, `OUTPUTTING`\n\n, `WAITING_INPUT`\n\n, `IDLE`\n\n, and `DISCONNECTED`\n\n; interaction modes are `AUTO`\n\nand `MANUAL`\n\n.\n\nImportant commands include:\n\n```\nshellink profile list --query '<name, host, or command>' --json\nshellink session create --profile <profile-id> --json\nshellink session state <session-id> --json\nshellink session exec <session-id> --command 'ls -la' --json\nshellink session input <session-id> --text 'yes' --json\nshellink session history <session-id> --since 0 --json\nshellink session download <session-id> --path /remote/file --output ./file --json\nshellink session upload <session-id> --input ./file --path /remote/file --json\nshellink session edit <session-id> --input edits.json --json\nshellink session close <session-id> --json\n```\n\nRemote editing accepts exact, non-overlapping replacements and requires an `AUTO`\n\nsession in `WAITING_INPUT`\n\n.\n\nThe repository includes two skills under `skills/`\n\n. Install with the\n[ skills](https://skills.sh/) CLI (\n\n`npx`\n\n). Always pass `--skill`\n\nso only the\nmatching subdirectory is installed (the repo contains more than one skill).\n\n```\n# List available skills\nnpx skills add jie123108/Shellink --list\n\n# shellink-cli (Codex example; see skills/shellink-cli/README.md for other agents)\nnpx skills add jie123108/Shellink --skill shellink-cli --agent codex\nnpx skills add jie123108/Shellink --skill shellink-cli --agent codex -g\n\n# shellink-iterm2-import\nnpx skills add jie123108/Shellink --skill shellink-iterm2-import --agent codex\n\n# Update\nnpx skills update shellink-cli\nnpx skills update shellink-iterm2-import\n```\n\nPer-agent install and update commands (Cursor, Claude Code, Codex, Pi, Trae,\nAntigravity, OpenClaw) are documented in\n[ skills/shellink-cli/README.md](/jie123108/Shellink/blob/main/skills/shellink-cli/README.md).\n\nUse this skill for profiles, SSH or command sessions, interactive input, file transfer, and remote editing. It requires a working `shellink`\n\nexecutable on `PATH`\n\n.\n\nUse this skill on macOS to scan and import iTerm2 Profiles and DynamicProfiles:\n\n```\npython3 skills/shellink-iterm2-import/scripts/import_iterm2.py --json\npython3 skills/shellink-iterm2-import/scripts/import_iterm2.py --dry-run --name \"Production\"\npython3 skills/shellink-iterm2-import/scripts/import_iterm2.py --guid <guid>\n```\n\nIt requires Python 3.9 or newer and an available `shellink`\n\nexecutable. Review scan results before using `--all`\n\n. Re-imports match by `uniqueId`\n\n(iTerm2 Guid) first, then by name; matching profiles are updated by default. iTerm2 passwords are not exported; add them later through the Web UI when necessary.\n\n| Variable | Description | Default |\n|---|---|---|\n`SHELLINK_HOME` |\nData, master-key, and PID directory | `$HOME/.Shellink` |\n`SHELLINK_SOCKET` |\nUnix socket path | Platform-specific runtime path |\n`SHELLINK_LOG` |\nDaemon log path | `$SHELLINK_HOME/shellink.log` |\n`SHELLINK_HTTP_ENABLED` |\nEnable HTTP/WebSocket compatibility services | `true` |\n`SHELLINK_HOST` |\nHTTP bind address | `127.0.0.1` |\n`SHELLINK_PORT` |\nHTTP port | `7070` |\n`SHELLINK_TOKEN` |\nAPI and Web UI token for remote access | `change-me` |\n`SHELLINK_REQUIRE_TOKEN_FOR_SENSITIVE_OPS` |\nForce token for session delete/purge (`true` /`false` ); unset derives from local vs remote |\nderived from request |\n`SHELLINK_MASTER_KEY` |\n32-byte key as 64 hex characters | Generated on first start |\n`SHELLINK_DB` |\nSQLite database path override | `$SHELLINK_HOME/shellink.db` |\n`SHELLINK_MAX_FRAME_BYTES` |\nMaximum RPC payload | `16777216` |\n`SHELLINK_SOCKET_MAX_QUEUE_BYTES` |\nMaximum buffered bytes per Unix-socket client before backpressure | `4194304` |\n`SHELLINK_SILENCE_MS` |\nQuiet-period threshold for state detection | `800` |\n`SHELLINK_EXEC_TIMEOUT_MS` |\nDefault command timeout | `30000` |\n`SHELLINK_TRANSFER_MAX_BYTES` |\nMaximum upload/download size | `6291456` |\n`SHELLINK_TRANSFER_TIMEOUT_MS` |\nDefault transfer timeout | `120000` |\n`SHELLINK_EDIT_TIMEOUT_MS` |\nDefault remote-edit timeout | `60000` |\n`SHELLINK_SSH_READY_TIMEOUT_MS` |\nSSH readiness timeout | `30000` |\n\nFor production, set `SHELLINK_MASTER_KEY`\n\nexplicitly and keep it stable for the lifetime of the database. The generated key is stored as `$SHELLINK_HOME/master.key`\n\nwith restrictive permissions.\n\n```\nnpm run dev                 # Server and Web UI\nnpm run dev:server         # Server only\nnpm run dev:web            # Web UI only\nnpm run build              # Production runtime build\n```\n\nThe project has unit, integration, protocol, CLI/TUI, WebSocket, and Docker-backed end-to-end tests.\n\n```\nnpm run test:protocol\nnpm run test:server\nnpm run test --workspace=cli\nnpm run test:server:coverage\nnpm run test:coverage:full --workspace=server\n```\n\nServer coverage uses Vitest's V8 provider and enforces these thresholds:\n\n| Metric | Threshold |\n|---|---|\n| Lines | 98% |\n| Statements | 98% |\n| Functions | 97% |\n| Branches | 90% |\n\n`test:server:coverage`\n\nexcludes the long-running `extreme`\n\nand `abnormal`\n\nE2E suites. Use `test:coverage:full`\n\nwhen Docker and the full integration environment are available. HTML and JSON coverage reports are written under `server/coverage/`\n\n.\n\nBug reports, feature proposals, tests, and documentation improvements are welcome. Please keep credentials out of commits, run the relevant test and build commands before submitting changes, and keep protocol changes synchronized across `protocol/`\n\n, `cli/`\n\n, and `server/`\n\n. Every code submission must include corresponding unit tests, and must not lower any of the coverage thresholds listed above.\n\nShellink is licensed under the [MIT License](/jie123108/Shellink/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts", "canonical_source": "https://github.com/jie123108/Shellink", "published_at": "2026-07-21 12:02:43+00:00", "updated_at": "2026-07-21 12:23:14.688845+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-infrastructure"], "entities": ["Shellink", "GitHub", "jie123108"], "alternates": {"html": "https://wpnews.pro/news/show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts", "markdown": "https://wpnews.pro/news/show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts.md", "text": "https://wpnews.pro/news/show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts.txt", "jsonld": "https://wpnews.pro/news/show-hn-shellink-let-ai-agents-run-commands-on-servers-behind-jump-hosts.jsonld"}}