Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

453 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Koi 𓆝

Let everything local find, trust, and talk.

Koi makes containers, applications, and devices delightfully discoverable, secure, and interconnected on your private network.

Bring container workloads onto mDNS. Give services meaningful .internal names. Establish shared identity and trust. Connect applications across container, host, and device boundaries. Observe them as they arrive, change, and leave.

One open-source, cross-platform binary. No hosted control plane. Built to work with the tools and networks you already have — even when the internet is unavailable.

Koi dashboard

Koi's promise has three parts:

Outcome What it means
🔎 Find Discover services over mDNS/DNS-SD, give them stable .internal names, and keep the view honest through leases and lifecycle events
🔐 Trust Give local names and peers shared identity through a private CA, guided enrollment, OS trust-store installation, mTLS, and diagnosis
🔗 Connect Let containers, host applications, devices, proxies, resolvers, monitors, and agents participate across their usual network boundaries

Label a container and Koi can announce, name, certify, and watch it without touching the image. A container can also discover and watch LAN services through ordinary HTTP, or bridge UDP without giving up network isolation. Participation works both ways.

Everything is reachable three ways: a CLI built for discoverability, an HTTP API with interactive docs, and a web dashboard with a live mDNS network browser.

koi mdns discover              # what's on this network?
koi dns add grafana 10.0.0.42  # give it a friendly name
koi certmesh create            # mint a private CA (guided)
koi status                     # one view of everything
koi launch                     # open the dashboard

Or over HTTP, from any language or script:

# Reads are open on localhost:
curl "http://localhost:5641/v1/mdns/discover?type=_http._tcp"

# Writes carry the daemon token (the CLI does this for you):
curl -X POST -H "x-koi-token: $TOKEN" http://localhost:5641/v1/mdns/announce \
  -d '{"name": "My App", "type": "_http._tcp", "port": 8080}'

The token lives in a breadcrumb file next to the daemon — see the security model for the two-line recipe per OS.

Quick start

Install with one line (detects your OS/arch, verifies the checksum, puts koi on your PATH):

curl -fsSL https://raw.githubusercontent.com/sylin-org/koi/main/install.sh | sh   # Linux / macOS
irm https://raw.githubusercontent.com/sylin-org/koi/main/install.ps1 | iex        # Windows

Then:

koi mdns discover        # works instantly, no daemon, no config

For always-on naming, trust, connectivity, and observation, run the daemon — foreground or as a system service:

koi --daemon             # foreground (Ctrl+C to stop)
sudo koi install         # or: install as a service (Linux/macOS)
koi install              # Windows (run as Administrator)

The daemon listens on 127.0.0.1:5641. Bare koi shows live status plus the full command catalog; koi <domain> shows curated examples; any command + ? (e.g. koi mdns announce?) opens a detail page.

Why Koi exists

Koi began as an mDNS bridge for containers. Containers live on the network, but their default bridge networks do not carry multicast, so they cannot naturally see or join the local discovery fabric. A small host service could speak mDNS on the physical LAN and expose it to isolated workloads through ordinary interfaces.

That solved the first gap and exposed the rest. A workload that can be found still needs a useful name. A named service still needs identity and trust. Containers, applications, and devices still need practical ways to communicate across their boundaries, and the entire picture has to change when something arrives, becomes unhealthy, or leaves.

mDNS itself illustrates why those seams exist. It is the invisible backbone of local networking — printers, smart speakers, AirPlay, Chromecast, and IoT devices use it — but using it programmatically is surprisingly painful:

  • Windows has native mDNS since Windows 10, but the Win32 APIs are poorly documented, 64-bit only, and don't expose full DNS-SD. The alternative — Apple's Bonjour — is effectively abandoned, with redistribution-prohibiting licensing.
  • Linux has Avahi: Linux-only, semi-maintained, deeply coupled to D-Bus and systemd. systemd-resolved's mDNS is famously flaky.
  • Containers can't do mDNS at all — bridge networks don't forward multicast, and every workaround (--network=host, macvlan, reflectors) sacrifices isolation or adds fragility.
  • Cross-platform libraries exist, but they're libraries: you re-implement discovery per language, and then hit the container multicast wall anyway.

Point solutions exist for most individual layers. The unowned problem is the connective tissue: letting a participant arrive, receive a name, be discovered, be reached, be trusted, report health, change, and leave cleanly. Koi owns those seams once, at the host and network boundaries, so every container and application does not have to solve them again.

Works with your stack

Koi is the substrate under the tools you already run, not a replacement for them:

  • Keep your DNS ad-blocker. Delegate one zone via conditional forwarding — Pi-hole/AdGuard/dnsmasq forward *.internal to Koi; everything else stays put.
  • Keep Tailscale. Point a tailnet split-DNS rule at Koi's resolver and remote devices resolve your LAN names; Koi covers the printers, TVs, and guests the tailnet can't see.
  • Keep your reverse proxy. Certmesh certs land as files with reload hooks for Caddy/Traefik/NPM today; an ACME endpoint (RFC 8555, dns-01, port 5643) lets your proxy renew against Koi like a local Let's Encrypt — see the ACME guide.
  • Ships now: Prometheus service-discovery export (GET /v1/sd/prometheus), MCP tools so AI agents can discover and trust local services, and reading the traefik.* / caddy labels your containers already carry.

The doctrine: export in their formats, consume what you already wrote, and make every capability easy to leave — tools that are easy to stop using are easy to start using.

How Koi delivers the outcomes

Find, Trust, and Connect are the product model. The implementation is a set of focused domains that compose at the daemon boundary:

Foundation:

Capability What it does CLI Guide
mDNS Service discovery with lease lifecycle koi mdns … mDNS guide
DNS Local resolver; names from three sources koi dns … DNS guide
Certmesh Private CA, guided enrollment, truststore install koi certmesh … Certmesh guide
Runtime Container lifecycle → announce/name/cert/watch via labels --runtime Runtime guide

Connectivity and operations:

Capability What it does CLI Guide
Proxy TLS endpoint for certmesh certs koi proxy … Proxy guide
Health HTTP/TCP checks feeding status & dashboard koi health … Health guide
UDP Host UDP sockets for bridge-networked containers koi udp … UDP guide
Trust Install/list/remove CA roots in the OS trust store; export the certmesh root; koi trust diagnose is the one-command trust-doctor koi trust … Trust protocol
MCP Expose the LAN to AI agents. koi mcp serve is the stdio transport; the running daemon also serves the same surface over Streamable HTTP at /v1/mcp (token-authed; default on, --no-mcp-http to disable) koi mcp serve MCP guide
ACME RFC 8555 server (dns-01, port 5643) so standard clients get certs from the CA koi certmesh acme … ACME guide

Every capability is runtime-toggleable (--no-dns, KOI_NO_DNS=1, …). The daemon also exports for tools you already run — a Prometheus HTTP-SD endpoint (GET /v1/sd/prometheus) and a DNS zone export (GET /v1/dns/zone?format=hosts|dnsmasq|json) — and serves the dashboard (/), the mDNS network browser (/mdns-browser), and interactive API docs (/docs).

A trust plane that's never silent

Every node carries a posture — Open until it has a mesh identity, mTLS once it does — and the same API behaves the same in both modes: messages can be signed (verified offline against the mesh root) or sealed, and listeners flip live between plaintext and mTLS without dropping connections. The category's defining failure is silent trust state (certs that expire unnoticed, mesh that's secretly plaintext), so Koi makes it loud: koi trust diagnose is the one-command health check — posture, identity and renewal health, integrity, revocation, CA-trust-install, clock skew, each with an exact remedy, exiting non-zero on anything red. The language-neutral wire contract is in the trust protocol reference.

Embedding: optional heavy backends

koi-embedded ships every backend by default. A lean consumer (e.g. a headless container that only needs discovery/DNS) can drop the heavy, version-locked ones with a single line — and re-arm any subset à la carte:

Cargo feature Default Pulls in Off → fallback
docker on bollard Docker/Podman client (=-pinned stubs) runtime backend → BackendUnavailable
keyring on OS keychain / Secret Service / D-Bus vault uses its passphrase backend
qr on qrcode + image PNG codec enrollment prints the otpauth:// URI
# everything (default) — unchanged
koi-embedded = "1.0.0-rc.1"
# lean: no bollard, no OS-keychain/D-Bus, no image codec
koi-embedded = { version = "1.0.0-rc.1", default-features = false }
# à la carte
koi-embedded = { version = "1.0.0-rc.1", default-features = false, features = ["docker"] }

See ADR-014. The koi binary always ships all backends.

Containers

Koi's container story — host daemon speaks multicast, containers speak plain HTTP — is the design center. The HTTP API binds to loopback by default, so it works out of the box with Docker Desktop (host.docker.internal); on native Linux, expose it deliberately with --http-bind bridge (or 0.0.0.0) and hand containers the token with koi token write (mutations still require it). CONTAINERS.md has the patterns, the secure exposure recipe, and the label-driven runtime adapter (the zero-code path).

OrbStack delivers a similar container-discovery inner loop, but only on macOS and as proprietary software; Koi is the open-source, cross-platform answer — the same story on Windows, Linux, and macOS.

Platform support

Platform mDNS engine Service integration
Windows Pure Rust (no Bonjour) Windows Service (SCM) + firewall rules
Linux Pure Rust (no Avahi) systemd unit
macOS Pure Rust (no Bonjour) launchd plist

Zero OS dependencies, single static binary, and — unusual for this space — Windows is a first-class citizen.

Installation

Install script (recommended) — picks the right release archive for your OS/arch, verifies its SHA-256, and installs onto your PATH. No root needed for the default per-user location; set KOI_INSTALL_DIR or KOI_VERSION to override.

curl -fsSL https://raw.githubusercontent.com/sylin-org/koi/main/install.sh | sh   # Linux / macOS
irm https://raw.githubusercontent.com/sylin-org/koi/main/install.ps1 | iex        # Windows

Container — multi-arch (amd64/arm64) image on GHCR:

docker run --rm ghcr.io/sylin-org/koi:latest version
docker run -d --name koi -p 5641:5641 ghcr.io/sylin-org/koi:latest   # daemon

Prebuilt binaries: download from GitHub Releases, extract, put koi (or koi.exe) on your PATH.

crates.io: cargo install koi-net remains the source-build escape hatch (the package is named koi-net — see Name below — and installs a koi binary). It needs a Rust toolchain; the recommended installer above does not.

The v1 release-candidate line carries an artifact manifest and cargo-binstall metadata, so Rust users can install the official prebuilt archive without compiling. Prereleases are deliberately explicit: use cargo binstall koi-net --version 1.0.0-rc.1 or npx @sylin/koi@1.0.0-rc.1. Stable unqualified commands remain on the latest stable release until Koi 1.0.0 ships. See ADR-025 for the artifact-first channel contract and its deliberately honest rollout states.

Build from source — requires Rust 1.92 or later:

git clone https://github.com/sylin-org/koi.git
cd koi
cargo build --release

Verify — every release binary and the container image carry a signed build-provenance attestation. A trust tool should let you verify its own supply chain in one line:

gh attestation verify koi-v1.0.0-rc.1-x86_64-unknown-linux-musl.tar.gz --repo sylin-org/koi
gh attestation verify oci://ghcr.io/sylin-org/koi:1.0.0-rc.1 --repo sylin-org/koi

Project status

Koi is at v1.0.0-rc.1: feature-complete for the v1 contract and ready for real-network evaluation. The release candidate brings the Find / Trust / Connect promise, artifact-first distribution, self-managing certmesh trust, truthful runtime recovery, and repeatable physical Windows/Linux validation into one candidate (CHANGELOG).

An RC is not the stable declaration: pin 1.0.0-rc.1, read the upgrade guide, and report anything that disagrees with the docs. The remaining road to 1.0 is defect discovery and contract hardening—not another expansion of scope. The assessment and validation record remain public under docs/assessment/ and docs/prompts/.

Documentation

Start here: the documentation hub is the goal-keyed map of every guide and reference. New to Koi? The Getting started tutorial goes from install to a visible result in about a minute, and Trusted HTTPS across two machines is the headline end-to-end journey.

Using Koi: User Guide · Container Guide · Security model

Capability deep-dives: mDNS · DNS · DNS coexistence · Certmesh · ACME · Runtime · Proxy · Health · UDP · MCP · Integrations · System · Embedded (Rust)

For AI agents: koi mcp serve runs a Model Context Protocol server over stdio (the daemon also serves the same surface over Streamable HTTP at /v1/mcp, token-authed), turning the LAN into a substrate an agent can read and act on — discover services, resolve and add names, take inventory, and announce the agent's own service (auto-heartbeated, auto-retracted on exit). See the MCP guide for the copy-paste client config.

Reference: Architecture · HTTP API · CLI · Wire protocol · Ceremony protocol · Envelope encryption

Decisions & direction: Find, Trust, Connect · Release channels · All ADRs · Assessment & roadmap

Name

Koi (鯉) are the fish that live in garden ponds. They're visible — they surface, they announce themselves by simply existing. You look into the pond and see what's there. That was the original service-discovery idea: the network is the pond, the services are the koi. The project grew beyond seeing what is there, but the name still fits its purpose—helping everything in the local environment participate rather than remain hidden behind a boundary.

The binary is koi. The crates.io package is koi-net because koi was taken.

Acknowledgments

Koi's mDNS heavy lifting happens in mdns-sd, a pure-Rust mDNS/DNS-SD implementation by @keepsimple1 — probing, conflict resolution, known-answer suppression, goodbye packets, and all the multicast plumbing. Koi gives it a friendly front door and builds the naming and trust layers on top.

License

Dual licensed under Apache-2.0 and MIT. See LICENSE-APACHE and LICENSE-MIT. Free to use, embed, bundle, and redistribute, commercially or otherwise — just link back to this project somewhere reasonable.

Contributing

See CONTRIBUTING.md — including how AI-assisted sessions should work in this repo (we eat our own dog food: see docs/prompts/CHARTER.md).

About

Local mDNS service discovery for everyone.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages