Skip to content

Add Wayfinder Provider (Local vs Hosted Router)#1966

Open
tcballard wants to merge 5 commits into
steipete:mainfrom
itsthelore:main
Open

Add Wayfinder Provider (Local vs Hosted Router)#1966
tcballard wants to merge 5 commits into
steipete:mainfrom
itsthelore:main

Conversation

@tcballard

@tcballard tcballard commented Jul 7, 2026

Copy link
Copy Markdown

Summary

Adds Wayfinder as a CodexBar provider.

Wayfinder is a self-hosted, deterministic local/cloud LLM router — its gateway runs on the user's machine and scores each prompt offline (no model call) to route it to a cheap/local or dearer/cloud tier. This provider polls the gateway's read-only JSON API and surfaces gateway health, the local/cloud routing split, savings versus always-cloud, and average routing decision latency.

Why

Users running Wayfinder currently have no way to see its routing activity from the menu bar alongside their other AI tool usage — they'd have to open Wayfinder's own dashboard separately. CodexBar already aggregates 50+ providers into one place; Wayfinder fits the same pattern as the existing ClawRouter integration (a router with a budget/usage split), so adding it here means one less place users have to check.

What Changed

  • Added the Wayfinder provider: descriptor, fetcher, and settings reader in Sources/CodexBarCore/Providers/Wayfinder/, following docs/provider.md.
  • Fetcher polls exactly four read-only gateway endpoints — /healthz, /router/models,/v1/savings?period=30d, /metrics — never the chat endpoints, and never reads or transmits prompt text.
  • No credentials required: the gateway's read endpoints are unauthenticated on loopback, so the only setting is an optional Gateway URL (defaults to http://127.0.0.1:8088), validated with the same loopback-HTTP policy already used by the CrossModel provider.
  • Added app-side settings field, menu card lines, CLI render lines, and a template icon (Sources/CodexBar/Providers/Wayfinder/, Sources/CodexBar/Resources/ProviderIcon-wayfinder.svg).
  • Wired the new provider through the existing registration points: UsageProvider/IconStyle enum cases, both provider registries, a new UsageSnapshot.wayfinderUsage field, and ProviderConfigEnvironment base-URL projection. All existing exhaustive switches over UsageProvider (widget colors/names, debug-log messages, cost validation) were extended for the new case — the compiler enforces this, so nothing else can silently break.
  • Added docs/wayfinder.md and a README/docs/providers.md entry.
  • Added tests: TestsLinux/WayfinderProviderLinuxTests.swift (16 tests) and a registry resolution test in Tests/CodexBarTests/WayfinderProviderTests.swift.
  • The provider is opt-in (defaultEnabled: false) — zero effect on existing behavior unless a user explicitly enables it.

Proof

Ran the actual wayfinder-router gateway locally (two stand-in OpenAI-compatible upstreams for a local and cloud tier, priced config) and sent it real prompts — easy ones stayed on the local tier, hard reasoning/math/constraint-heavy prompts escalated to cloud under Wayfinder's lexical routing. 14 requests total: 10 local / 4 cloud, 61.5% saved. Fetched through the real provider code via the CLI:

Before: no Wayfinder provider exists in CodexBar; a user running the gateway has to check its own dashboard separately.

After:

$ codexbar usage --provider wayfinder --source api
== Wayfinder (api) ==
Gateway: ok · 2 models
Routed: local 10 · cloud 4
Saved: <$0.01 · 61.5% vs always-cloud
Avg decision: 0.1 ms
Plan: Local Gateway

Failure path (gateway not running), showing the error is actionable:

$ WAYFINDER_GATEWAY_URL=http://127.0.0.1:9999 codexbar usage --provider wayfinder --source api
Error: Could not reach the Wayfinder gateway. Start it with `wayfinder-router serve`
(default http://127.0.0.1:8088) or fix the Gateway URL in Settings.

Menu card screenshot: to be added — see Risk section.

Validation

Automated tests:

  • swift test --parallel — full suite green: 107 tests across 18 suites, including 16 new Wayfinder tests plus a registry-resolution test. The Wayfinder tests use the live gateway responses above as fixtures (not hand-written JSON): full/empty/degraded/unpriced response variants, UsageSnapshot mapping, Prometheus metrics parsing (missing/garbage/labeled lines), URL normalization, loopback-HTTP endpoint policy (accepts 127.0.0.1/localhost, rejects other plain-HTTP hosts, accepts any HTTPS), config→environment projection, Codable round-trip, an endpoint-set pinning test (proves the fetcher only ever calls the 4 documented paths), HTTP error mapping, same-origin/redirect rejection, and CLI text rendering.
  • swiftformat Sources Tests --lint (0.61.1, matching this repo's pinned CI version) — clean, 0 files need formatting.
  • swift build -c release --product CodexBarCLI — clean.
  • Portable lint checks from Scripts/lint.sh (generated-hash check, package/product paths, repository size, documentation links) — all pass.

Manual testing: exercised the provider end-to-end against a real, locally running Wayfinder gateway (not mocked) via the CLI, on Linux, including both the healthy path and the gateway-unreachable failure path shown above.

Not yet verified:

  • swiftlint --strict — could not be run as CI would in the environment this was developed in (no outbound access to fetch the pinned release binary, and a from-source build of the same version crashed on any input there — confirmed unrelated to this diff since it crashed identically on pre-existing files too). The diff was reviewed by hand against every rule in
    .swiftlint.yml with no findings, but this repo's CI run will be the first real confirmation.
  • The macOS app target (CodexBar) itself — only the cross-platform CodexBarCore and CodexBarCLI targets were built and tested, on Linux. Every macOS-only exhaustive switch was extended for the new case, but hasn't been compiled/run on macOS yet.

Risk

  • Auth/credentials: none — the gateway's read-only endpoints are unauthenticated on loopback, so this provider introduces no new credential handling.
  • Provider routing: none — this only reads Wayfinder's own gateway; it never calls /v1/chat/completions or anything that could route a prompt.
  • Persistence/migration: none — one new optional field on UsageSnapshot (wayfinderUsage), additive and Codable-compatible; no schema migration needed.
  • Settings: adds one new optional config field scoped only to the .wayfinder provider (Gateway URL); no existing provider's settings are touched.
  • Existing workflows/UI: additive only — new enum case, new registry entries, new renders lines gated on snapshot.wayfinderUsage != nil. Every existing exhaustive switch was extended (compiler-enforced), so no other provider's behavior changes. The provider defaults to disabled.
  • Known limitations: no macOS screenshot yet, and swiftlint --strict hasn't had a real run (see Validation). Opening as a draft for that reason — will flip to ready once verified on macOS.

Notes for Review

The three files worth actually reading:

  • Sources/CodexBarCore/Providers/Wayfinder/WayfinderUsageFetcher.swift — the core fetch/parse logic and the UsageSnapshot mapping.
  • Sources/CodexBarCore/Providers/Wayfinder/WayfinderSettingsReader.swift — the loopback-HTTP validation policy (mirrors CrossModel's).
  • TestsLinux/WayfinderProviderLinuxTests.swift — the live-gateway-fixture tests.

Everything else in the diff is mechanical wiring into existing registration points (enum cases, registries, exhaustive switches) — shouldn't need line-by-line attention.

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 2:43 PM ET / 18:43 UTC.

Summary
The branch adds a default-off Wayfinder provider with read-only gateway polling, a Gateway URL setting, menu/CLI/widget wiring, docs, icon resources, and tests.

Reproducibility: yes. for the review finding: source inspection shows configured Wayfinder fetches use the projected Gateway URL while the dashboard action still falls through to the descriptor's default URL. The provider itself is feature work, so general bug reproduction is otherwise not applicable.

Review metrics: 2 noteworthy metrics.

  • Diff surface: 25 files changed, +1078/-4. The provider touches core, app UI, CLI, widget, docs, and tests, so macOS app proof matters before merge.
  • Provider default: 1 provider added, defaultEnabled=false. The opt-in default limits existing-user blast radius while still requiring validation for users who enable Wayfinder.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🦐 gold shrimp
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix the dashboard URL so it follows the configured Wayfinder Gateway URL.
  • [P1] Add redacted macOS app proof showing the settings field and menu/dashboard behavior.
  • Report make check or the closest macOS SwiftLint/build equivalent once available.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR has real terminal CLI output against a local gateway, but it does not yet show the macOS settings/menu behavior changed by the branch; add redacted screenshot, recording, terminal output, or logs and update the PR body to trigger re-review.

Risk before merge

  • [P1] Users who configure a non-default Wayfinder Gateway URL can get successful polling while the Usage Dashboard action opens the wrong or unreachable default gateway.
  • [P1] Contributor proof covers live CLI output against a real gateway but not the freshly built macOS settings/menu behavior touched by the PR.
  • [P1] The PR body says swiftlint --strict and the macOS app target were not run in the contributor environment, so CI or maintainer validation still needs to cover those paths.

Maintainer options:

  1. Fix settings-consistent dashboard (recommended)
    Derive the Wayfinder dashboard URL from the validated Gateway URL and add focused coverage for a custom gateway before merge.
  2. Accept default-only dashboard behavior
    Maintainers could intentionally ship the default dashboard URL only, but custom-gateway users would see inconsistent settings behavior.
  3. Pause provider bundling
    Pause or close the PR if Wayfinder should not be accepted as a built-in provider yet.

Next step before merge

  • [P1] Human review should wait for the dashboard fix, contributor-supplied macOS proof, and maintainer direction on accepting Wayfinder as a built-in provider.

Maintainer decision needed

  • Question: After the dashboard and proof blockers are fixed, should CodexBar accept Wayfinder as a built-in default-off provider?
  • Rationale: VISION.md encourages provider additions that follow existing patterns but still calls new features and provider additions with privacy/maintenance implications sign-off work.
  • Likely owner: steipete — The product-scope decision is best routed to the repository owner and existing provider/dashboard pattern owner.
  • Options:
    • Accept after blockers (recommended): Land the built-in provider once the dashboard URL follows the configured gateway and macOS proof/checks are added.
    • Defer provider scope: Keep the PR open or close it later if maintainers decide Wayfinder should not be bundled as a core CodexBar provider.

Security
Cleared: No concrete security or supply-chain concern was found; the provider is default-off, adds no dependencies or credentials, validates endpoint overrides, and pins read-only polling endpoints in tests.

Review findings

  • [P2] Use the configured gateway for Wayfinder dashboards — Sources/CodexBarCore/Providers/Wayfinder/WayfinderProviderDescriptor.swift:21
Review details

Best possible solution:

Derive the Wayfinder dashboard URL from the same validated configured gateway base URL used for polling, add redacted macOS app proof, and then have a maintainer decide whether to accept Wayfinder as a built-in provider.

Do we have a high-confidence way to reproduce the issue?

Yes for the review finding: source inspection shows configured Wayfinder fetches use the projected Gateway URL while the dashboard action still falls through to the descriptor's default URL. The provider itself is feature work, so general bug reproduction is otherwise not applicable.

Is this the best way to solve the issue?

No, not yet. The provider architecture follows local patterns, but the dashboard action should use the same configured gateway base URL as polling before this is maintainable.

Full review comments:

  • [P2] Use the configured gateway for Wayfinder dashboards — Sources/CodexBarCore/Providers/Wayfinder/WayfinderProviderDescriptor.swift:21
    Wayfinder polling honors the saved Gateway URL through ProviderConfigEnvironment and WayfinderSettingsReader, but this descriptor always points the dashboard at the default 127.0.0.1:8088 instance. Because StatusItemController.dashboardURL has no Wayfinder branch and falls back to meta.dashboardURL, a user configured for http://localhost:9099 gets a working poller and a Usage Dashboard button that opens the wrong gateway. This prior blocker is still unfixed.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against aa401f1d8b74.

Label changes

Label justifications:

  • P3: This is an optional, default-off provider feature with limited existing-user blast radius.
  • merge-risk: 🚨 compatibility: The PR adds a Gateway URL setting but currently leaves the dashboard action pointing at a hard-coded default gateway.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR has real terminal CLI output against a local gateway, but it does not yet show the macOS settings/menu behavior changed by the branch; add redacted screenshot, recording, terminal output, or logs and update the PR body to trigger re-review.
Evidence reviewed

What I checked:

Likely related people:

  • steipete: The existing dashboard helper, provider registry baseline, and ClawRouter provider pattern trace through Peter Steinberger commits, and this PR needs product-scope provider acceptance. (role: baseline provider and dashboard-area owner; confidence: medium; commits: a83a83fa4131, efb7839ddf99, b5b1a1ae4f37; files: Sources/CodexBar/StatusItemController+Actions.swift, Sources/CodexBarCore/Providers/ClawRouter/ClawRouterProviderDescriptor.swift, Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift)
  • JC: The Wayfinder implementation mirrors CrossModel's loopback-friendly provider pattern, and CrossModel was introduced in a recent provider-addition commit. (role: adjacent provider pattern contributor; confidence: low; commits: 0a18391e1838; files: Sources/CodexBarCore/Providers/CrossModel, Sources/CodexBar/Providers/CrossModel)
  • Hinotobi: Recent security hardening commits shaped the endpoint override validator that this PR correctly reuses for Gateway URL validation. (role: endpoint-boundary contributor; confidence: low; commits: 23e33cd3deba, ba16332c3c21; files: Sources/CodexBarCore/ProviderEndpointOverrideValidator.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-07-07T07:20:33.612Z sha 4fdb0a8 :: needs real behavior proof before merge. :: [P2] Render the actual route buckets
  • reviewed 2026-07-07T18:25:58.816Z sha 297be11 :: needs real behavior proof before merge. :: [P2] Use the configured gateway for Wayfinder dashboards
  • reviewed 2026-07-07T18:31:03.894Z sha 297be11 :: needs real behavior proof before merge. :: [P2] Use the configured gateway for Wayfinder dashboards

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fdb0a84d1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

toggleTitle: "Show Wayfinder usage",
cliName: "wayfinder",
defaultEnabled: false,
dashboardURL: "http://127.0.0.1:8088/router",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the configured Wayfinder URL for the dashboard

When a user overrides the Wayfinder Gateway URL (for example to http://localhost:9099), fetches use that override via the projected environment, but the menu's Usage Dashboard action falls through StatusItemController+Actions.dashboardURL to this hard-coded metadata URL for Wayfinder. In that configuration the dashboard button opens the default 127.0.0.1:8088 instance, which is wrong or unreachable even though polling succeeds against the configured gateway.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. labels Jul 7, 2026
@tcballard

Copy link
Copy Markdown
Author

Pushed a fix for the route-summary assumption (commit 4cbf4ab).

Root cause: routedSummary read models.models.first?.name and treated array position as
"the local tier." /router/models has no field asserting that — route names are just whatever the user named their own endpoints.

Fix: removed the local/cloud guess entirely. routedSummary now renders the real per-route breakdown by name (e.g. groq-8b: 10 · openai-o1: 4), matching the existing ClawRouter pattern
in this repo instead of swapping in a different fragile heuristic (endpoint-host sniffing has
the same problem — a local model isn't guaranteed to be on loopback).

Tests added (TestsLinux/WayfinderProviderLinuxTests.swift): heavier-traffic route
configured second (no positional reliance), and arbitrary route names asserting the summary
never contains "local"/"cloud". Docs updated to match. 109/109 tests green, formatting clean.

Still open (unchanged by this push, already noted in the PR body): no macOS screenshot,
and swiftlint --strict hasn't had a real run in my dev environment (sandbox network restriction; a from-source build crashes on any input there, confirmed unrelated to this diff).

This push should trigger CI on macos-15-intel, which will give a real answer on both.

The gateway's /router/models has no field asserting which configured
route is "local" - route names are whatever the user named their own
endpoints. Render the real per-route breakdown by name (matching the
existing ClawRouter pattern) instead of guessing from array position.
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label Jul 7, 2026
@tcballard

Copy link
Copy Markdown
Author

@clawsweeper re-review please

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant