bind-host

A technical guide for binding a computer as a trusted host in the mpx command-line tool. It describes how the host proves its identity and how the tool shares a connection payload using a QR code, Bonjour, or optional clipboard copying.

In plain words
What is it for?
Use it when implementing or reviewing host binding, mpx bind and unbind commands, key handling, QR or Bonjour setup, and the related repositories and protocol.
Why use it?
It clarifies the security decisions behind adding a machine and distinguishes the public key from the private key. This reduces the risk of exposing credentials or breaking the documented distribution setup.

Agent

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add agents/multiplex-term/multiplex/bind-host
Clone the repo
git clone --depth 1 https://github.com/multiplex-term/Multiplex
Per session 0 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 1,436 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00000 $0.01436
Opus 5 $0.00000 $0.00718
Sonnet 5 $0.00000 $0.00287
Haiku 4.5 $0.00000 $0.00144

Measured yesterday against content hash 489e0b18a8cf, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

bind-host scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

docs/agents/bind-host.md · 82 lines

How it starts

The opening of the file, as written. The whole thing — 82 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Bind Host & the mpx CLI

Load-bearing decisions split from AGENTS.md.

  • A bound host is one the machine itself vouched for; the app's key goes out, never a private key (Models/Bind/, Services/Bind/; protocol + shared vectors in the companion repo multiplex-term/multiplex-cli, spec/bind-v1.md). mpx bind runs on the machine being added and offers itself three ways: terminal QR, Bonjour announcement, and opt-in clipboard (mpx bind --copy — the payload is credential-grade and must not ride Universal Clipboard by default; the pane prints the command beside its Paste button). The app generates an ed25519 keypair; the CLI appends the public half to authorized_keys with the multiplex:bind:<8 hex>:<device-slug> comment (mpx unbind's handle). Distribution is three repos: closed source in multiplex-term/multiplex-cli (never promise it will open; [email protected] does not exist — problems go to the releases repo's issues), archives in multiplex-term/multiplex-cli-releases, and multiplex-term/homebrew-tap (the homebrew- prefix is brew's own resolution rule for the tap multiplex-term/tap — renaming 404s every documented install line). A v* tag builds four targets (musl + darwin, x86_64/aarch64), publishes SHA256SUMS, opens a formula bump; needs the cross-repo RELEASE_TOKEN. multiplexterm.dev/install-mpx-cli (multiplex-home repo) covers macOS AND Linux and refuses SHA mismatches. The OFFER carries the host's SSH key fingerprints into Host.pinnedHostKeys, which HostKeyVerifier enforces on every connection — so a bound host is verified from its first dial, against a set the machine itself vouched for, while a manually added host only gets trust-on-first-use. That is the security argument for binding, and it is why the OFFER's hostkeys array must stay complete: the validator refuses an algorithm no pin covers (HostKeyPin.decide), so a machine that offers a key type its OFFER omitted cannot connect until the user forgets its keys in Host Settings. Load-bearing: the free host limit is checked before the handshake (a key must not land in authorized_keys for a host this tier can't use); a payload from outside the modal never auto-binds (onOpenURLBindController.receive only adds a candidate row and raises the pane for an explicit ENROLL — a multiplex://b/… URL is attacker-suppliable; the pane's own scan/paste keep auto-confirm, and the machine still asks [Y/n]); the machine's own address list outranks wherever its listener answered (BindNaming.hostname; mpx bind --addr covers NAT — the reached address wins only when the machine endorses it); the PIN proof is transcript-bound (HKDF over PIN + both public keys, 3 attempts then the session locks) while a wrong token closes silently (counting 128-bit guesses would gift a LAN spammer a DoS). Two announcements claiming one name raise a caution on both rows (BindAnnouncement.contestedNames; discovery dedupes by session key, so a shared name means two keys claiming one machine). It is a tell, not a control — do not let it grow into one: the same unauthenticated mDNS lets an attacker forge a goodbye for the real row or answer for its instance name and leave a single row standing, and two mpx bind runs on one machine contest their own name, which is why the copy says "if you started only one". The fix that doesn't depend on someone noticing is a SAS over spub (spec/bind-v1.md §3). The whole flow is one modal: Add Host opens on BIND | MANUAL (AddHostSheet.Mode); the deck has no bind surface at all (chip, rail, and ghost tiles shipped and were withdrawn 2026-07-28). Discovery browses only while bindSurfaceOpen OR an enrollment is in flight — in-flight specifically, or a row parked on FAILED holds the browser open behind a closed modal. A row retires when the machine withdraws its announcement — every way mpx bind ends does that (Ctrl-C via the CLI's cancel module); fix endings in the CLI, never with an app-side liveness probe (tried and rejected 2026-07-28: Bonjour resolves to dead aliases and deleted live machines). The one non-false-positive backstop: BindOfferLifetime retires rows older than the CLI's --expires ceiling (600 s) + margin — keep in step with the CLI's clamp or move the expiry into the TXT record. --offline (a VPS reachable only over SSH) inverts the key direction — the CLI ships a private key in the payload — so the app retires it on first connection (BindRotationStore: append BEFORE remove; a failure between the steps must leave a working key). The bind key passphrase lives in the app, nowhere else (BindPane KEY PASSPHRASE; applies to handshake and offline-seed alike). Empty = plaintext store. Set → the key is sealed as encrypted openssh-key-v1 by BindSSHKey.sealedPrivateOpenSSH (vendored mpxbind_-prefixed OpenBSD bcrypt-pbkdf + CommonCrypto; Citadel's independent bcrypt is the decrypt side, making the round-trip test a real cross-check); the passphrase saves into the host's settings (synced Keychain, the same slot Host Settings shows/clears) so the probe connects immediately. A sealed key is never rotated, and save() skips the probe for a sealed key with no passphrase on file. The CLI knows nothing about passphrases (a CLI-side variant shipped and was reverted 2026-07-29).

Read the full file on GitHub · 82 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday First seen · 82 lines · 0 tokens per session scan A 489e0b18a8cf

Subscribe to this mod's changes

bind-host is an agent published in the GitHub repository multiplex-term/Multiplex (10 stars, last pushed 5d ago), licensed Apache-2.0. It costs nothing until one of its globs matches a file; then it loads 1,436 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.