WayfinderRouter scores a request offline, then picks a model
Simple CLI tool for deterministic routing of queries between local and hosted LLM models
At a glance
- What is it?
- asdecided/WayfinderRouter is a Rust model router built around Omarchy: one loopback endpoint, a deterministic offline decision that records a receipt, and credentials resolved only after the route is chosen. Its plugin, container and managed data plane each refuse to take custody of your provider keys.
- Who is it for?
- Fit for a developer who already has several models on the machine and wants one endpoint that keeps choosing sensibly without a network call in the decision path, and for teams that need a fail-closed surface with virtual keys rather than a shared credential.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One endpoint, and a receipt for every choice
The premise is that a developer on Omarchy already has models and AI tools installed, and what is missing is a single endpoint in front of them. Wayfinder provides that, and for each request it selects an eligible local, account-backed or API model, then records a deterministic receipt explaining the choice.
The three eligibility classes are the interesting part of the design. A local model is one already running, an account-backed model is one reached through a signed-in account rather than a billed API key, and an API model is a conventional credential-based destination. One router covering all three means the client configuration does not change when you move work between them.
The decision itself has constraints that are stated repeatedly and are worth repeating as the core claim: the scored decision path stays offline, deterministic and keyless. Credentials are resolved only for delivery, after the route has been chosen.
That ordering is the whole safety argument. A router that needs a credential to decide cannot be reasoned about offline, and a router that decides differently run to run cannot be debugged. Wayfinder tries to be both auditable and reproducible, and `wayfinder-router open` exists so a person can read the local routing decisions rather than infer them.
The shell never becomes the routing authority
The flagship surface is an Omarchy plugin, installed with a plugin add command and enabled in one step. It is a thin wrapper: it installs the checksum-verified Router release, manages an independent `systemd --user` service, and surfaces health, recent routes, model readiness, local-versus-hosted usage and savings in the native Omarchy bar.
Two boundaries are stated as principles rather than features. The shell never becomes the routing authority, and it never takes custody of provider credentials. Reloading or disabling the plugin does not interrupt the Router, because the Router is a separate process with its own service.
The setup flow is designed to remove the usual Linux friction. In the Omarchy bar you choose Set up Wayfinder, and the native flow installs the checksum-pinned Router when it is missing, creates a no-clobber local policy, validates that policy, then installs and starts the user service. It needs no Rust, no Cargo, no hand-written unit file and no copied endpoint.
Underneath, the Router is a portable Rust project with no Omarchy runtime dependency at all, which is what allows the plugin, the container and the desktop apps to share one routing core.
Model discovery is a bounded probe, not a download
The behaviour that separates this from a model manager is what it refuses to do. When a local runtime is present, the Router discovers model identifiers only from fixed loopback catalogs, and it proves a loaded model with one bounded public inference probe.
It never downloads, pulls, selects or activates a model silently. That is four specific refusals, and together they mean the router cannot quietly spend disk, start a service or change which model an agent is talking to.
The error path is designed too. If a provider requirement is missing, the panel names the requirement and the next safe action, rather than surfacing a failed request or an empty list. A router that can tell you which credential is missing is more useful than one that retries.
The hosted side follows the same discipline from the other direction. Adding a hosted destination is done through a reviewable provider preset fragment, and the command prints the official compatibility endpoint plus an environment variable reference. It never writes a credential and never edits routing policy, so the change stays something a person can read before it takes effect.
connect writes configuration, exec promises not to
There are two ways to point a client at the router, and the difference is whether anything is written to the client's own configuration.
`wayfinder-router connect <client>` is the reviewable path. It is what you use for Codex, Claude Code, OpenCode, Pi and Aider, and the documented quick starts live in a coding agents guide. `wayfinder-router exec <client> -- <program>` is the alternative, and its guarantees are specific: it is a no-write launcher, it validates Router readiness and the client's wire capability first, it applies only process-local endpoint, model and placeholder-token overrides, and it never falls back to the direct provider.
That last clause is the important one. An agent that cannot reach the router fails instead of quietly going direct, which is the difference between a policy you can rely on and a policy that depends on connectivity.
Omarchy can launch Codex, Claude Code or OpenCode through the same policy with exec. Pi is deliberately left on connect, and the reason is stated: it stays on the reviewable path until its CLI exposes a verified no-write endpoint override. That is a refusal to guess about someone else's CLI, and it is the kind of limitation that is cheaper to find in the README than in production.
The managed data plane is the only surface meant to be exposed
There are two listeners, and the instruction for a network deployment is explicit: do not publish the local surface. Instead mint a virtual key and select the fail-closed managed data plane.
rust/target/debug/wayfinder-router keys new --id team-a
rust/target/debug/wayfinder-router serve \
--surface data-plane --host 0.0.0.0 --port 8088The naming is the point. A virtual key is not a provider credential; it is something you mint for a consumer of the gateway, and the managed surface is described as fail-closed, which is a promise about behaviour when something is missing rather than a best effort.
What the managed listener contains is narrow: inference, authenticated model discovery, and minimal liveness and readiness probes. Nothing else. A deployment guide exists for it under the documentation directory.
Everything else about the shipped binaries reinforces this. SemVer releases on the router tag line also provide checksum-verified native Linux archives for x86_64 and aarch64, and the README is explicit that installing an archive does not create or start a service and does not alter provider credentials. You get a binary, not an installation.
Two compatibility surfaces on one port
The gateway answers on a single port and speaks two protocols, which is what lets one router serve both agent families without configuration changes on the client side.
The OpenAI-compatible surface is at `/v1` on the local host, and on top of it sits an OpenAI Responses compatibility endpoint at `POST /v1/responses`, described as bounded text, multi-turn, and the function and custom tool contract used by Codex. The Anthropic-compatible surface is at the root of the same port. Health is at `/healthz`.
Modality support is where the honesty is. There are explicit capability contracts for embeddings, image, audio and batch, and the non-text surfaces remain fail-closed until their reviewed adapters are enabled. So the router states what it will not do rather than accepting a request and degrading quietly.
The Rust workspace behind this holds the deterministic scoring core, the configuration parser, the provider clients, the bounded HTTP gateway, service integration, native XPC clients and a command-line helper, which is a reasonable inventory for a component that has to run inside someone's desktop session as well as inside a container.
The container runs as uid 10001 and compiles a benchmark fixture
The Dockerfile is a two stage build, and the second stage contains very little:
docker build -t wayfinder-router .
docker run --rm -p 8088:8088 \
--read-only --tmpfs /tmp --user 10001:10001 \
-v "$PWD/config:/etc/wayfinder:ro" \
-v wayfinder-state:/var/lib/wayfinder \
wayfinder-routerThe builder is `rust:1.85-bookworm` and the runtime is `debian:bookworm-slim` with ca-certificates installed and nothing else, so no Rust and no build toolchain ship in the final image. The user is created with uid and gid 10001, with no home directory and a home of `/nonexistent`, and `/etc/wayfinder` is owned by root while `/var/lib/wayfinder` is owned by that uid at mode 0750. Configuration is therefore read-only to the process while audit and savings state is writable.
Two details are worth reading closely. The build copies a fixture from `benchmarks/blind/openai-cross-provider.jsonl` into the builder stage, so a blind benchmark file is a build input rather than test-only material. And the default command starts the data plane with an explicit config path, which means a container run without a mounted config has no virtual key and no model, and will not start usefully.
The Makefile is the four target developer loop: build, route, test and lint, with lint running both the formatter check and clippy with warnings treated as errors.
Mobile is paused, and the architecture is written down anyway
Three products are described, and one of them is deliberately stopped. The iPhone and iPad roadmap is paused while the project focuses on the Omarchy developer experience, with the accepted architecture still recorded so the work can resume without changing the portable routing core or weakening provider and privacy boundaries.
That recording is more than a note. The paused mobile effort is governed by named documents: a roadmap for native mobile, three architecture decision records covering native mobile independence, a shared routing core with Apple embedding, and mobile conversation persistence, plus a design contract for the thread-first mobile chat shell. A paused project that has already decided its constraints is cheaper to restart than one that has not.
The macOS app is the live counterpart. A native Swift application with conversation-first chat and locally persisted history, automatic or pinned model selection, Apple Foundation Models delivery on eligible Apple Silicon Macs, native Anthropic Messages destinations with bounded streaming and tool translation, opt-in ChatGPT account routing through a separately verified provider, and its own local gateway endpoints. Its releases use SemVer on a separate `desktop-v` tag line from the router's.
The thin clients over the gateway are an npm workspace at version 0.0.0 with a single parity script, which is a candid way to say that the JavaScript side is a thin layer whose behaviour is checked against the native API rather than a product in its own right.
Editorial conclusion
Fit for a developer who already has several models on the machine and wants one endpoint that keeps choosing sensibly without a network call in the decision path, and for teams that need a fail-closed surface with virtual keys rather than a shared credential. A poor fit for a hosted deployment, since the managed data plane carries inference, authenticated discovery and health probes only, and a poor fit if you want the app to fetch weights for you, which the router explicitly refuses to do. Before exposing anything, mint a virtual key and start the data plane rather than publishing the local surface, and read the audit and savings files, since those are where the routing decisions you are being asked to trust actually land.
Frequently asked questions
What does Wayfinder do?
Wayfinder is a Rust model router built for Omarchy that gives one local endpoint for the models already on the machine. For each request it selects an eligible local, account-backed or API model and records a deterministic receipt explaining the choice, with the scored decision path staying offline, deterministic and keyless so credentials are resolved only for delivery.
How do I expose WayfinderRouter on a network?
Do not publish the local surface. Mint a virtual key with wayfinder-router keys new --id team-a, then start the fail-closed managed data plane with serve --surface data-plane --host 0.0.0.0 --port 8088. That listener carries inference, authenticated model discovery and minimal /livez and /readyz probes only.
Can I use WayfinderRouter without Rust or Cargo?
Yes, through the Omarchy plugin, whose setup flow installs the checksum-pinned Router when it is missing, creates a no-clobber local policy, validates it, and installs and starts the user service, with no Rust, Cargo, hand-written unit file or copied endpoint. Building from source is also supported with cargo build against rust/Cargo.toml for the wayfinder-cli package.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/asdecided-wayfinderrouter)