Repository navigation
Releases: siebe41/SemanticRouter.NET
Releases · siebe41/SemanticRouter.NET
Release list
v0.5.0
Added
GET api/setupfor the dashboard's first-run setup: whether a model is still needed, whatsemantic-router initwould find on this machine (LM Studio, Ollama, and the claude, codex and copilot CLIs with whether they are signed in) and one-click provider presets (LM Studio, Ollama, OpenAI, Anthropic, OpenRouter, Google Gemini, Claude Code, Codex, GitHub Copilot). It only describes; nothing is enabled until the dashboard applies it. The machine policy, offline mode and the allowed endpoints leave out what they turn off (offline, no CLI is started to ask). Like a change, it is refused from other sites, so a page elsewhere cannot set off the CLI checks;?refresh=truereuses a look younger than 10 seconds, and a detection that fails still answers with the presets and the problem indetectionProblem.POST api/connectors/discoverdiscovers the models of a connector that is only in the dashboard's draft, held to the same checks as applying it (policy, what a CLI may run, where a stored secret may go). The audit log records where it asked (scheme://host:port, or a CLI's program).POST api/config/saveandPOST api/config/revert, andunsavedinGET api/status: a configuration applied without saving can be kept or undone, and the dashboard can say it is not saved.PUT api/config?baseVersion=N&instance=Xrefuses a change made against a version that is no longer running (409with who changed it, when and how), so two editors cannot silently undo each other.instance, a random id for this run of the router, is in every configuration envelope andGET api/status: version numbers start again at 1 on every start.- Validation errors from
PUT api/configandPOST api/config/validatecome withissuesthat name the field (Routes.1.Name,Connectors.local.Timeout), and a value that does not fit its field says the format it needs ("5m" is not a duration; use hh:mm:ss, e.g. 00:05:00) instead of "Expected a configuration document". - The
semantic-routertool and the desktop app redirect/to the dashboard (MapRouterDashboardRedirect; an application's own/endpoint wins). - The start-up banner has a Try it block: a request to send (curl, or
Invoke-RestMethodon Windows), where to watch it on the dashboard (#/live), and the Claude Code command as one line with its variables inline, as in the client guide. While no model is enabled it says so instead, with the link to the setup on the dashboard's Overview. - The container seeds a connector for
OPENAI_API_KEYandANTHROPIC_API_KEYon the start that creates the configuration file (deleting one sticks); the connector refers to the key as${env:…}, so the key never lands in the file (SEMANTIC_ROUTER_SEED_API_KEYS, on in the image). doctorchecks the Codex CLI's sign-in withcodex login status.- Desktop app: on the first start the dashboard opens on its Overview, where the setup is, and the welcome window says so. While the router has no enabled model, the tray menu says so and offers the setup, with one notification.
- README: a Quick start right under the introduction (who it is for, what to install, the commands, the desktop app, where to go next).
- Dashboard: Running configuration not saved in the top bar when the router runs a configuration that was applied without saving, with Save and Revert to saved for the admin (the More panel shows the source as "not saved").
- Dashboard: the save bar counts the draft's changes, and Review shows them next to the running configuration.
- Dashboard: Apply names the version the draft started from; when someone else applied a configuration meanwhile, a notice says who and when and offers Reload, Compare or Apply mine anyway. The refresh notices such a change too (a router restart included): it reloads a draft without changes quietly, and moves unapplied edits onto the new configuration when they touch other settings. Moving them is strict: a new order of model aliases, routes or models, or a list such as CLI arguments changed on both sides, is a conflict; only lists that are sets (utterances, capabilities and similar) combine.
- Dashboard: removing a route, model, connector, profile, tier, budget or memory source offers Undo; removing a connector that models use, or a profile that rules, virtual models, client mappings or budgets name, asks whether to remove those too.
- Dashboard: problems from Validate and Apply are shown next to their fields (the item opens, the first gets the focus), and the problem list links each one to its field on its page.
- Dashboard: model aliases can be reordered (the first matching glob wins).
- Dashboard: new Activity entries that arrive while the table holds still (auto-refresh off, a label being written, text selected) are counted, with Show.
- Dashboard: Set up SemanticRouter on the Overview while no model is enabled: add a connector (tools found on this machine first, then presets for LM Studio, Ollama, OpenAI, Anthropic, OpenRouter, Gemini and the CLIs), add models (Discover models, Apply & save), send a test prompt. Read-only users see that an admin needs to add a model.
- Dashboard: Add connector is a menu of presets and a blank connector, also shown on an empty Connectors page.
- Dashboard: Activity has a search box, and a click (or Enter) on a row opens the whole decision.
- Dashboard: Router learned has a small Settings form for the common
Tuningoptions. - Dashboard: Routes can be set to follow the conversation (
FollowsConversation).
Changed
- Dashboard: the 19-link sidebar, which no longer fit a laptop screen or the desktop app's default window, is a narrow rail of five sections (Monitor, Routing, Providers, Gateway, Admin) with each section's pages as tabs under the top bar. Routing rules is the Rules tab and the gateway page the Settings tab. Report an issue (the Feedback page) sits at the foot of the rail, and the version, theme picker and Sign out moved under More. Every page keeps its address, so existing links and bookmarks still work.
- A request no model can serve because of the configuration (no model enabled, or none with the tier, capabilities, locality or profile it needs) gets
400 invalid_request_errorin the client's protocol instead of503, so the SDKs and Claude Code stop retrying, with what to do and where: "SemanticRouter has no model that can answer this (no model is enabled). Add one on the dashboard: http://localhost:5080/router#/overview". Failed or cooling-down models still give a retryable503, as do a prompt that could not be classified (the embeddings did not answer) and a request only models outside their active hours would fit ("no model is in its active hours right now"). - The "no model is enabled" warning and service note point to the dashboard's setup on Overview instead of the Models page or
semantic-router init. initreplaces a configuration that still holds the built-in template (as the router writes it on its first start) without--force; a file whose embeddings someone chose is not the template.initoutput: a one-line tier legend, no similarity-threshold note, the Claude Code command on one line (noexport) and only when a model is enabled; with none, the dashboard's setup. When a subscription CLI is all it found, the question says that without it the router has no model to use.doctor: no enabled model is a[FAIL](exit code 1), whose fix is a step that helps (the dashboard's setup, orinitwhile the configuration is still the template). Fix lines name the dashboard field beside the setting, e.g. Providers → Connectors → openai → API key.- An unreachable LM Studio or Ollama says how to start it (Developer → Start server,
ollama serve); other servers name the address setting and where it is on the dashboard. - A failed ONNX model download names huggingface.co,
HTTPS_PROXYandNetwork:CaBundle, and where to copy the file instead, and is logged without a stack trace. - A quieter console: ASP.NET Core's lines per request and the hosting start-up notes from
Warning, data protection fromError(the router's own key-ring line covers it); the router keeps its one line per request.Logging:LogLevelturns any of it back up. - The key-ring warning (unencrypted keys, macOS and Linux) appears only once the secrets file holds a key.
- An address that is in use is explained without a stack trace; when this configuration's own router holds that address, the message says so with its dashboard address.
- Links in the tool's output, the help text and the desktop app point to the documentation site instead of files in the repository.
deploy/compose.yamlruns the published imageghcr.io/siebe41/semantic-router:<version>; building from the checkout is a commented-out alternative.- The site's Get started (home page and top bar) goes to the README's Quick start; its Try it names the .NET 10 SDK and the Claude Code line.
- Dashboard: Apply & save is the primary action; Apply is now Apply only ("a restart undoes it").
- Dashboard: Discard, Use defaults (tiers, complexity rules), revert, reset, rollback and the other confirmations ask in the page instead of the browser's dialog; Discard says how many changes go and offers Undo.
- Dashboard: the top bar's health dot shows the router's overall state (red when failing or no model is enabled, amber when degraded or warming up), with a label, and a short word next to it on a phone.
- Dashboard: messages stack instead of replacing one another, are spoken once (errors as alerts, prefixed so), and "Not applied" stays until it is closed; the top bar and banner are rewritten only when they change.
- Dashboard: a button is marked busy while its action runs and cannot be sent twice.
- Dashboard: the read-only role sees forms as read-only (no add or remove buttons, no Send in the prompt tester), and is not asked before leaving.
-...
v0.4.0
Added
- Desktop app: an Updates section in About SemanticRouter, and Check for updates now… in the tray menu. It shows whether the app is up to date and when it last checked, an update that is downloading, ready or available, and why a check failed or updates are off. It has Check now, Restart to update and the two update switches.
What's Changed
- Release signing check: accept ALLOW_UNSIGNED_RELEASE with stray spaces or capitals by @siebe41 in #167
- Documentation site on GitHub Pages, with a home for the demo videos by @siebe41 in #168
- Changelog: the Unreleased changes shipped as 0.3.0 by @siebe41 in #169
- Bump mermaid from 11.17.2 to 12.1.0 in /site in the site group by @dependabot[bot] in #170
- Add a kit that records a marketing demo video of the router by @siebe41 in #166
- Desktop app: an Updates section in the About window by @siebe41 in #171
Full Changelog: v0.3.0...v0.4.0
v0.3.0
Security
- Machine-wide policy that the user's configuration cannot override, read from
HKLM\Software\Policies\SemanticRouter, macOS managed preferences or/etc/semantic-router/policy.json: turn off connector types and CLI presets, limit endpoints and the hosts that count as local, require local-only, cap prompt storage and retention, make the dashboard read-only or turn it off, control desktop updates and turn features off. A policy that cannot be read stops the router. See docs/enterprise.md. (#142) initdoes not add, or ask about, CLIs that the machine policy turns off. (#146)- Offline mode (
Network:OfflinewithNetwork:AllowedHosts, orOfflinein the machine policy): connectors, embeddings and webhooks reach only this machine and the allowed hosts, CLI and Copilot connectors are off, and the ONNX model is never downloaded. (#147) - Remote gateway clients need a key: with no
Middleware:GatewayKeysthey get 401 (AllowUnauthenticatedRemoteClientsrestores the old behaviour), and a key reference that does not resolve no longer opens the gateway. The container image readsROUTER_GATEWAY_KEY. (#129) - Default limits for remote clients (
Middleware:RemoteRequestsPerMinute, 120) and CLI queues (MaxQueue, 16), andForwardedHeaders:KnownProxies/KnownNetworksto trustX-Forwarded-Foronly from named proxies. (#129) - Web pages cannot use the gateway through DNS rebinding or a foreign
Origin;/v1/models,count_tokensand/semantic-router/classifyfollow the same gateway-key rule as the chat endpoints. (#114) - Dashboard responses forbid framing (
frame-ancestors 'none',X-Frame-Options: DENY) and sendnosniffandno-referrer; the dashboard bundles its fonts and sends a strict Content-Security-Policy. (#114, #129) - The admin API cannot change what a CLI runs (program, arguments, environment, home directory) or which paths memory sources read, unless
Dashboard:AllowProcessSettingsis on. (#114, #144) - The read-only dashboard role can no longer trigger calls that cost money or scan the disk (evaluate, classify, embeddings test, discover, check, memory refresh); dashboard sessions expire after
Dashboard:SessionLifetime(12 hours), and wrong tokens are throttled per address. (#144) - Dashboard identity from an authenticating reverse proxy (
Dashboard:TrustedIdentityHeader, believed only fromKnownProxies), the real actor on every configuration change, and an append-only audit log (GET /router/api/audit, an Audit log page,State:Retention:AuditDays). (#150) - A
Metricsdashboard role (Dashboard:MetricsToken, orMetricsinTrustedIdentityRoles) that sees figures only, never prompt or reply text. Signing out ends the session on the server, and an admin can sign out every session (POST /router/api/session/revoke-all); sessions from before the upgrade sign in once more. (#161) - With
State:StorePrompts: Off, a failed CLI run's output and the judge's reason for a grade are not stored or logged either;Redactedmasks credentials in them. (#162) - Local-only routing holds in more cases: a failed classification stays local while any route is local-only, a conversation kept local stays local (including named cloud models), local-only prompts stay off remote embedding endpoints (
Embeddings:IsLocal), and the judge respects routing profiles. (#114) - Secrets: CLI environment variables and more header names (auth, cookie, password, credential, session, signature) are masked; masked or stored keys are never sent to a connector that now points somewhere else; the configuration history keeps no secrets; keyed requests do not follow redirects; webhook URLs are not logged. (#114, #116)
- Keys written into addresses (
user:key@, key-named query values) are masked in the admin API, the configuration history and every address the dashboard anddoctorshow. (#117, #129) - CLIs run in a working directory only the user can write to and start by full path; a Custom CLI's
{prompt}cannot become an option; the router's files are readable by their owner only. (#114) - The data-protection key ring is encrypted at rest: to a certificate (
DataProtection:Certificate) on any OS, with DPAPI forSEMANTIC_ROUTER_KEYS_DIRon Windows; otherwise owner-only permissions and a start-up warning.doctorsays how the keys are protected. (#149) - Stored prompts:
State:StorePrompts(Redactedby default, masking credentials in previews;On;Off),State:Retention, and a purge (DELETE /router/api/activity, "Delete all activity") that leaves nothing readable in the database files. (#129) - Webhooks carry no prompt or reply text unless
Notifications:IncludeDetailsis on, and the stored project label is a hash of the client'suser_id, never the id. (#144) - Prompted tool calls are harder to forge: a random fence label per run that never reaches the client, defused tool results,
PromptedToolParsing: Strict(opt-in), calls copied from a tool result kept as text in both modes, and a prompted-call count in the activity log. (#129, #152) - No outbound traffic you did not configure: no web fonts from other hosts, Claude Code started without its auto-updater and non-essential traffic, Codex with update checks and analytics off.
doctorlists every host the router will contact. (#129, #143) - Desktop updates:
Updates:Publisherrequires an update to be code-signed by a given publisher before it is applied, and the updater refuses feeds over plain HTTP other than loopback. (#142, #151) - Verifiable releases: build provenance attestations for every asset,
SHA256SUMS, CycloneDX SBOMs, a keyless cosign signature and attestations on the container image, andTHIRD-PARTY-NOTICES.txt. See docs/releases.md. (#145) - Release pipeline: a tag must be on
main, tests pass before anything publishes, the desktop app is built in jobs without secrets, and the image is built and scanned (Trivy) before the registry login. CodeQL and OpenSSF Scorecard run on the repository. (#129) - The container runs on a chiseled ASP.NET Core image with no shell, with both base images pinned by digest. (#129)
- NuGet restores are locked to committed
packages.lock.jsonfiles in CI, the release and the container build. (#148)
Added
- A "Cut a release" workflow (Actions > Cut a release): the repository owner enters a version, it checks CI, code signing and NuGet publishing, tags
main, and the release workflow publishes everything with the CHANGELOG section as the release notes. Only the owner can release, by this workflow or a pushed tag. See docs/releases.md. - Cache-aware stickiness: a conversation stays on the model with the warm prompt cache when that is cheaper than moving, and returns to it after a failover (
Middleware:Conversation:CacheLifetime). (#137) - Prompt-cache markers on Anthropic requests translated from OpenAI or Responses clients (
Connectors:{name}:PromptCaching,CacheTtl). (#139) - Cache reads and writes per activity entry, and a cache hit rate on the Usage page. (#113)
- Endpoints card on the Overview (host, state, health and latency per connector, with a Check button) and a Service card (where the router runs, the URLs for clients, its health). (#117, #121)
Network:CaBundle, a PEM file trusted in addition to the system store, for TLS-inspecting proxies. (#143)- Desktop app: notify-only updates (
Updates:Apply: Notifyin the machine policy, or "Install updates when quitting" in the tray), and managed deployment docs. (#151) PromptRouterMiddlewareOptions.InjectedTags; the Copilot app's injected context blocks are ignored when classifying. (#118)- Model names
semantic-router,claude-semantic-router,-cheapestand-best;/v1/modelsentries have adisplay_name. (#156) tool-callsbenchmark for prompted tool calling. (#152)- A
quick-answersroute (tier 2) in the starting routes, for short factual and explain questions, and small-refactor utterances insimple-code; the sample evaluation set has 116 prompts. (#160) - Dashboard Feedback page and a Report button on each Activity entry: they open a GitHub issue (misroute, bug or idea) with the decision line, the model that answered, the embedding settings and the router version filled in. The prompt is left out unless you add it, and a local-only prompt answered by a cloud model points to private security reporting instead. The misroute and bug forms ask for the router version and the decision line. (#164)
Changed
- Targets .NET 10 (LTS) instead of .NET 9, whose support ends on 10 November 2026: the packages and the tool need the .NET 10 runtime, and the container runs on ASP.NET Core 10. Building needs a 10.0.4xx SDK. (#115, #148)
initasks before enabling a subscription CLI connector (Claude Code, Codex); declined or non-interactive runs add it disabled.--yesrestores the old behaviour and--no-clileaves CLIs out. (#141)- Prompts go to Claude Code and Copilot CLIs on standard input;
PromptInput: "Argument"restores the old behaviour. (#114) - Model comparisons count each model's prompt-cache prices, from the share of input it reads from cache (
Selection:CacheShareWindow,CacheShareSamples). (#138) - Only the prose of a prompt is embedded, without pasted code or data (
EmbedProseOnly, on by default); local-only routes are still checked against the whole prompt. (#157) - The
inittemplate routes Claude Code's*opus*asauto;opus-pinnedpins Opus, and an exact alias wins over a wildcard. (#156) - Routing profile
Projectsglobs match the hasheduser:…project label, and dashboard sessions sign in once more after the upgrade. (#144) - Dependency updates, among them GitHub.Copilot.SDK 1.0.22. (#134, #135, #136)
Fixed
- Cached-token counts on streamed and translated replies, from the CLIs and in "saved by routing". (#113)
- After a failover, the serving model is timed from ...
Site Media
Merge pull request #166 from siebe41/siebes/pensive-mayer-921bpq Add a kit that records a marketing demo video of the router
v0.2.1
What's Changed
Full Changelog: v0.2.0...v0.2.1
v0.2.0
v0.1.0
What's Changed
- Add SemanticRouter: semantic prompt routing for .NET 9 by @siebe41 in #1
- Pin NuGet restore to nuget.org with a repo nuget.config by @siebe41 in #2
- Anthropic front door for Claude Code, a hot-reload dashboard, named tiers and a roadmap by @siebe41 in #20
- Secrets out of the config file, dashboard tokens and gateway keys, LM Studio authentication by @siebe41 in #21
- Add the semantic-router tool and container; run CI on Windows and macOS by @siebe41 in #22
- Durable state: cooldowns, tool-call affinity, activity and configuration history by @siebe41 in #23
- Usage, cost and budgets; limit reset times; OpenTelemetry traces and metrics by @siebe41 in #24
- Responses API front door for Codex; thinking, structured output and dropped features across protocols by @siebe41 in #25
- Land the host, durable state, usage and protocol work on main by @siebe41 in #26
- Routing quality loop: evaluation sets, threshold calibration, route health, labelling activity by @siebe41 in #27
- In-process ONNX embeddings, a classification cache and warm-up statistics by @siebe41 in #29
- Add memory map: track notes sent to models in requests by @siebe41 in #28
- Routing profiles: policy per client, project and content by @siebe41 in #31
- Land the routing-quality work (#27) on main by @siebe41 in #30
- Faster prompted CLI turns, and a Copilot connector on GitHub's official SDK by @siebe41 in #32
- Dashboard: end-to-end tests in CI, accessibility, phone layout and drop-in themes by @siebe41 in #33
- Add model lineup discovery and suggestions for connectors by @siebe41 in #34
- Add desktop app and background service support by @siebe41 in #35
- Desktop: fit the window to the screen, About window; fix Windows CI by @siebe41 in #36
- Windows update script; SQLite state no longer drops bursts of writes by @siebe41 in #37
- Improve CLI queue test reliability with synchronization by @siebe41 in #38
- Fix Windows CI (SQLite handle leak); safer update-windows.ps1 by @siebe41 in #39
- Desktop app owns the background service; route by the conversation (#41); explicit callouts (#42) by @siebe41 in #51
- Record implicit outcome feedback per routing decision (#43) by @siebe41 in #52
- Tune thresholds and utterances automatically, within guardrails (#45) by @siebe41 in #53
- Track model reliability per kind of work (#44) by @siebe41 in #54
- Model-family priors: tiers and capabilities from a curated table (#46) by @siebe41 in #55
- Default routes and evaluation prompts for agentic clients (#47) by @siebe41 in #56
- Optional judge that grades a sample of cheap answers (#48) by @siebe41 in #57
- Weekly digest; notify only when a decision is needed (#49) by @siebe41 in #58
- Installers for the desktop app: Setup.exe, .pkg, AppImage (#50) by @siebe41 in #59
- Add CODEOWNERS and a ruleset that protects main by @siebe41 in #60
- Ready the first release: install CI on every OS, signing, durable counts (#63–#66) by @siebe41 in #75
- Harden the repo for public use: CI gates, least-privilege release, security and contributor docs by @siebe41 in #61
- Fix the formatting gate on main; installer jobs follow the release hardening by @siebe41 in #77
- Bump the actions group across 1 directory with 6 updates by @dependabot[bot] in #76
- Bump the nuget-minor-and-patch group with 10 updates by @dependabot[bot] in #78
- Bump Microsoft.Data.Sqlite from 9.0.20 to 10.0.12 by @dependabot[bot] in #81
- Bump coverlet.collector from 6.0.4 to 10.1.0 by @dependabot[bot] in #79
- Send notices and the weekly digest to webhooks by @siebe41 in #84
- Bump FluentAssertions from 7.2.2 to 8.11.0 by @dependabot[bot] in #80
- Bump Microsoft.NET.Test.Sdk from 17.12.0 to 18.10.1 by @dependabot[bot] in #82
- Bump xunit.runner.visualstudio from 3.0.2 to 4.0.1 by @dependabot[bot] in #83
- Ship the client side-request wording as an updatable data file by @siebe41 in #85
- Per-client rate limits for gateway keys by @siebe41 in #86
- Fuzz tests for protocol translation, and the crashes they found by @siebe41 in #87
- Recognise corrections in other languages and other words by @siebe41 in #88
- Measure how often the judge agrees with hand labels by @siebe41 in #89
- Learn the cheapest good-enough model per route by @siebe41 in #90
New Contributors
- @siebe41 made their first contribution in #1
- @dependabot[bot] made their first contribution in #76
Full Changelog: https://github.com/siebe41/SemanticRouter.NET/commits/v0.1.0