Remote & Agentic Access · via hop

Same tap,
from anywhere

Install hop alongside tap and your Linux host's session inventory becomes available to authenticated peers — operators on a laptop, AI agents through MCP, fleet automation. Same kernel capture, same opener-attribution, same audit trail. tap stays a local-first Linux tool; hop adds the network layer.

Setup AI & MCP

Where each tool fits

tap is a Linux audit primitive. hop is a peer-to-peer fleet runtime. They're independent products that compose cleanly.

tap, by itself

A local Linux daemon plus a CLI. Captures every TTY/PTY via eBPF, exposes a permission-aware Unix socket, lets root and individual users audit the sessions they own. Doesn't reach off the host. Doesn't have a network stack at all.

hop, by itself

A peer-to-peer remote-access daemon. QUIC over iroh, Ed25519 identities, an extension protocol for plugins, an MCP server for AI agents, a JS runtime for capabilities. Doesn't know anything about your terminals.

tap + hop

tap registers with hop as an extension (manifest at /etc/hop/extensions/tap-terminal.toml). hop relays peer-authenticated requests to tap's daemon over a Unix-domain ipc-channel. tap applies hop's peer/role identity to its existing scope check — no new permission model, just the same opener-aware filtering keyed on the calling peer's identity.

Architecture — tap + hop
+-------------------- Laptop / agent host -----------------+ | | | hop <target> tap list / snapshot / watch | | hop mcp (Claude / Cursor / etc. via MCP) | +-----------------------|----------------------------------+ | iroh QUIC, peer-authenticated v +------------------ Linux host ----------------------------+ | | | hop host (systemd, listens for peer connections) | | | | | | ipc-channel (manifest rendezvous) | | v | | hop-tap-d ────── /run/hop-tap/local.sock (SO_PEERCRED) | | | ^ | | | eBPF kprobes | | | v | | | kernel pty subsystem tap (local CLI) | +----------------------------------------------------------+

Setup — three steps

Install order matters: bring up hop first so tap's installer registers the extension automatically.

Install hop

One curl. Sets up the host daemon and prints a creator invite token for first-time pairing.

curl -fsSL https://hop.keik.ai/install-daemon.sh | bash

Install tap

One curl. Detects the running hop daemon and registers itself as an extension automatically.

curl -fsSL https://tap.keik.ai/install.sh | bash

Pair, then drive

Redeem the invite from your laptop, then run any tap command remotely.

hop connect <invite-token>
hop <host> tap list
Terminal — remote audit
$ hop myserver ext list tap.terminal (active) Terminal session capture via eBPF $ hop myserver tap list 2 active session(s): pty= 3 user=alice(1000) comm=bash pid= 3214 ... pty= 4 opener=alice(1000) writer=root(0) comm=sudo ... $ hop myserver tap snapshot 3 snapshot pty=3 (24x80) ┌─... $ hop myserver tap watch 3 (stream 1 opened) # Live byte stream over QUIC, rendered natively by your terminal.

The permission model, networked

tap's local "root sees all, users see their own" model lifts to "creator role sees all, peer role sees their own opener_username" when called through hop.

creator role

Admin tier. The peer who originally bootstrapped the host (and anyone they explicitly grant the role to). Sees every active session, can subscribe to any pty's live byte stream, can snapshot anything.

peer role

Default for invited users. tap's scope check matches peer_username (forwarded from hop's authenticated dispatcher) against each session's opener_username. Same sticky-opener semantics as local — sudo can't escape your scope.

Same denial wording

Forbidden snapshot/watch returns the same error as a non-existent pty. Peers can't enumerate other users' active sessions by probing — both tiers, locally and remote.

Trust boundary

tap trusts hop's peer authentication (Ed25519 + invite tokens) as forwarded in ExtMessage::Request's peer_role. tap doesn't re-verify identity — that's hop's job, and tap inherits the verdict.

AI agents, via hop's MCP

hop ships an MCP server. Agents that speak Model Context Protocol — Claude, Cursor, Code editors with MCP support — get tap as a tool.

How agents see tap

An AI agent connecting to hop mcp can list sessions, request snapshots, and subscribe to live streams the same way a human peer can. The MCP boundary is the same QUIC-authenticated boundary peers use; the agent's identity is the agent's hop peer.

What you'd build with it

A Claude agent watching production hosts for anomalies (long-running sudo, unexpected scrub of audit logs, unusual command patterns). A code-review bot that pulls the most recent shell session of an SRE for context when triaging. Auto-narrated incident timelines, generated from session-replay snapshots.

Same trust gradient

An agent peer running with creator role sees everything, naturally. A scoped agent (peer role, pinned to a specific username) sees only that user's sessions — useful for self-audit agents the user runs against their own activity.

  • → Agent observes; doesn't drive (no input injection in v1)
  • → Snapshots are bytes, not LLM-summarized; agent runs its own model
  • → Audit trail is hop's existing peer-event log; agent activity is logged like any other peer
MCP — agent calling tap through hop
// AI agent (Claude Code, etc.) starts an MCP session // against the local hop daemon. From the agent's POV: agent.tools.call("hop_remote", { target: "prod-web-1", cmd: "tap list", }); // Agent can iterate. Watch a session for 30 seconds, // summarise what's happening, decide whether to alert. var sessions = JSON.parse(stream.list); for (s of sessions.filter(s => s.opener_username === "alice")) { var snap = agent.tools.call("hop_remote", { target: "prod-web-1", cmd: `tap snapshot ${s.pty_index}`, }); // LLM analyses snap, decides if interesting }

Ready to wire it up?

Both tools are independent, single-binary installs. Bring up hop first, then tap; the extension wires itself in automatically. Same audit story, networked.

hop → tap, locally