kinjo 0.1.0

Kinjo: mDNS TUI and commands launch for local network services
Documentation

Kinjo

Browse local DNS-SD services, filter them, and run custom actions from a terminal UI.

GitHub Release Crates.io docs.rs GitHub branch check runs Quality Gate Status License: MIT

What's it for?

Avahi, the common Linux implementation of Bonjour / mDNS / DNS-SD, allows services to be published and discovered on a local network. This TUI lets users browse discovered services, filter and group them, and launch configured actions for a selected service.

Launch the TUI without arguments to browse the default local domain:

kinjo

Browse another DNS-SD domain with the --domain (-d) flag:

kinjo --domain example.local

For development without a running Avahi setup:

kinjo --fake-discovery

The app discovers services over mDNS/DNS-SD so no external CLI tools are required. Two discovery backends are available, selectable with --backend:

  • mdns-sd (default): the mdns-sd-discovery crate. A single browser enumerates every service type on the link via the native DNS-SD meta-query.
  • zeroconf: the zeroconf-tokio crate, which talks to the system Avahi daemon on Linux. It browses one service type at a time, so a curated set of common types is swept in parallel when no --service-type is given. This backend is behind the off-by-default zeroconf cargo feature (it needs the Avahi client headers to build, e.g. libavahi-client-dev on Debian/Ubuntu):
cargo install kinjo --features zeroconf
kinjo --backend zeroconf

When a --service-type is given, only that type is browsed. If mDNS discovery is unavailable, it falls back to sample records so the UI remains usable.

Installation

Debian / Ubuntu

Download the latest .deb package from the project's GitHub Releases page, then install it with apt:

sudo apt install ./kinjo_*_amd64.deb

The package installs kinjo and the bundled system command files under /etc/kinjo/commands.

For real local-network discovery, make sure Avahi is installed and running:

sudo apt-get update
sudo apt-get install -y avahi-daemon
sudo systemctl enable --now avahi-daemon

Cargo

Install from crates.io with Cargo:

cargo install kinjo

On Debian or Ubuntu, install native build dependencies first:

sudo apt-get update
sudo apt-get install -y clang libavahi-client-dev libxcb-shape0-dev libxcb-xfixes0-dev xorg-dev

Build From Source

Clone the repository and build locally:

git clone https://github.com/abbyssoul/kinjo.git
cd kinjo
cargo build --locked

Run from the source tree:

cargo run -- --fake-discovery

Install the built binary into Cargo's bin directory:

cargo install --path .

Smoke Test

You can verify the UI without a running Avahi daemon:

kinjo --fake-discovery

To browse real services on the default local domain:

kinjo

How It Works

kinjo has five moving parts:

  1. Discovery finds DNS-SD service records on the network. Each record can carry fields such as service name, service type, domain, hostname, address, port, and TXT values.
  2. Filtering and view tabs organize those records in the UI. You can fuzzy-search the visible services, limit by service type, and switch the top-panel tab to view discovery by service, host, service type, or matching command.
  3. Actions decide what can be done with a selected service. Action command files define match predicates such as "service type equals _ssh._tcp" or "TXT field contains a URL".
  4. Command templates turn service fields into executable commands. For example, ssh {hostname} uses the selected service hostname, while xdg-open http://{hostname}:{port} builds a URL from the selected instance.
  5. Keybindings control the TUI. The defaults use Vim-style navigation, and every built-in UI command can be rebound in keybindings.toml.

The result is a small local service browser that behaves like a configurable launcher: discover services, narrow the list, choose a matching action, and run the command built from that service's fields.

Architecture

Internally those moving parts live in three deliberately decoupled modules, so the project is easy to extend and hack on. Each is designed to be swapped or reused independently:

  1. Discovery (src/discovery/) — the producer of entries. An entry is a discovered record described entirely by its attributes (name, type, host, address, port, TXT, …). A backend implements the Discovery trait and emits Entry values; Entry is the only contract the rest of the program depends on. The mDNS/Avahi backend is the default, with a built-in sample backend for --fake-discovery — but you could drop in a different DNS-SD source, a static file, or an SSDP/UPnP browser without touching anything else.
  2. Plumber (src/plumber/) — the rules engine. A serializable collection of command rules (the TOML command files) is matched against entries by their attributes; multiple rules can match one entry, and a matching rule can be executed. It depends only on Entry, never on the UI, and sits behind a RuleEngine trait so an alternative matching strategy can be substituted.
  3. UI (src/ui/) — ties discovery and the rules engine together for a person at the terminal: CLI parsing, config and keymap loading, the application state machine, and rendering. It depends on the other two; they do not depend on it.

The dependency flow is one-directional — discovery ← plumber ← ui — wired together in main.rs. The two trait seams (Discovery and RuleEngine) are the intended extension points: implement a trait, swap it in at the composition root, and experiment. See CONTRIBUTING.md for development setup.

UI

Default keys follow Vim-style conventions:

  • j / down: move down
  • k / up: move up
  • enter: show or run matching actions
  • /: fuzzy text filter
  • t: service type checklist filter
  • tab / shift+tab (or / ): switch view tab
  • r / F5: refresh — restart service discovery from scratch
  • ?: help
  • q: quit

The top panel exposes four tabs — services, hosts, types, and commands. Each tab swaps the list and details panes to view discovery from that angle: individual services, hosts and the services they offer, discovered service types, or configured commands and the services they match. The list also supports fuzzy text search and service type filtering.

Keybindings are fully customizable: all built-in UI commands can be rebound with a keybindings config file. See docs/keybindings.md for the full keybinding reference and examples.

Configuration

Command files follow the XDG Base Directory Specification. User command files are loaded from:

$XDG_CONFIG_HOME/kinjo/commands/*.toml

If XDG_CONFIG_HOME is not set, the fallback path is:

~/.config/kinjo/commands/*.toml

Additional command directories can be provided with:

kinjo --config-dir ./commands

Validate and list the registered commands with:

kinjo list-commands

To validate and list only the commands from a specific directory:

kinjo list-commands --config-dir ./commands

A running instance reloads its command files on SIGHUP (the conventional reload signal), so edits apply without restarting the TUI:

pkill -HUP kinjo

Keybindings can be overridden at:

$XDG_CONFIG_HOME/kinjo/keybindings.toml

See docs/keybindings.md for examples and the complete list of bindable commands.

Command Files

Each command file defines one action and structured match predicates. Example SSH opener:

[metadata]
name = "ssh"
description = "SSH into a service"
requirements = ["ssh"]

[match.service_type]
equals = "_ssh._tcp"

[action]
description = "SSH into the selected service"
command = "ssh {hostname}"
mode = "execute"

Supported action modes:

  • fork: spawn the command and return to the TUI.
  • execute: restore the terminal and replace the TUI process with the command.

Supported match predicates:

  • equals
  • contains
  • regex

Supported service fields:

  • name
  • service_type or type
  • domain
  • hostname
  • address
  • port
  • txt.<key>

The same fields can be used in action command interpolation, for example {hostname}, {address}, and {port}.

Multiple configured actions can match the same service. In that case, the TUI shows an action picker. If an action needs instance-specific fields such as address or port and the selected row contains multiple instances, the TUI asks which exact instance to use.

For the full command file format, examples, and overlay rules, see docs/actions.md.

Contributing

Development setup, required system packages, and local verification commands are documented in CONTRIBUTING.md.