Files
OmniRoute/AGENTS.md
Diego Rodrigues de Sa e Souza f165efcd0b Release v3.8.28 (#4053)
* chore(release): open v3.8.28 development cycle

* fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (#4063)

The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module
inside the connection handler, only on the API-key path. That cold import pulls
in hundreds of transitive modules and takes ~7s under tsx, blocking the
single-threaded event loop. The first API-key WebSocket connection therefore
stalled the loop long enough that any connection arriving in that window — e.g.
a same-origin cookie client — could not complete its handshake and timed out.

This was deterministic, not an "env flake": the boot test fires an API-key
connection immediately followed by a cookie connection, so the cookie connection
always raced the cold import and timed out (reproduced 3/3 locally and red on
every CI run; proven via instrumented probes — reversing the order or warming
the module first makes both connections open in ~20ms).

Fix:
- Memoize the auth-module import and warm it once at startup (before listen), so
  connection handling never pays the cold-import cost. Real improvement: the
  first API-key client no longer stalls the event loop for concurrent clients.
- Relocate the boot test from tests/unit/cli to tests/integration. It spawns a
  real subprocess + WS server + SQLite (~9-11s); under the unit suite's
  --test-concurrency=20 it contended for CPU and destabilized the shard. The
  serial integration runner is its correct home; it still guards #4004's
  cookie-parse fix on every PR via the integration CI job.
- Bump the test's startup/overall timeouts to absorb the eager auth warm.

Makes `npm run test:unit` deterministically green (the only remaining unit red).

Validated: relocated test 3/3 green via the integration runner (was 3/3 red);
typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob
and does match tests/integration/*.test.ts.

* fix(ws): start LiveWS sidecar with cwd at package root (#4055) (#4064)

* chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (#4045)

Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only).

* deps: bump electron from 42.4.0 to 42.4.1 in /electron (#4049)

Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente #3913/#3914 (electron dependabot mergeado nessas condições).

* fix(auto): resolve built-in auto catalog combos (#4058)

Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes.

* chore(docs): update Discord invite link to a non-expiring one (#4067)

* chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (#4066)

Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado #4014). Fast QG + semgrep + dast verdes.

* ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (#4069)

The pre-existing release unit test-debt that kept the TIA "Impacted unit tests"
step advisory has been cleared:
- #4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors).
- #4063 fixed the last red — the LiveWS boot test — which was a real deterministic
  event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second
  connection), not an env flake; fixed (warm the import at startup) and relocated to
  the integration suite.

A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests
shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing
and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift).

Removing continue-on-error makes PR->release block on unit-test regressions in the
TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped
changes). typecheck:core was already blocking. Closes the fast-gates "no tests on
PR->release" hole (Quality Gate v2 / Fase 9, P2).

* docs(compression): document LLMLingua optional deps + on-demand install (#4061)

Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1).

* feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (#4068)

Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1).

* feat(compression): record Context Editing telemetry (engine: context-editing) (#4062)

Integrado em release/v3.8.28. Context Editing telemetry (F4.1).

* feat(sse): Context Editing relay coverage + 400-fallback (#4065)

Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs #4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente #4034/#4020).

* feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (#4070)

Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente #4034/#4065).

* test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (#4078)

* test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4

Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env
var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened
the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns
one per sandbox, so this shared file caused cross-file state races:
- SQLite lock contention that hung `npm run test:unit` under high --test-concurrency
  (the ~95-min local hang), and
- the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which
  in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled
  2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2.

open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production
(bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would
point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY
tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is
set (tests that set DATA_DIR explicitly still win), wired via --import into the test,
mutation and CI invocations.

Verified:
- Stryker dry-run A/B at concurrency=4: FAILS without the isolation import
  (account-fallback-service tap exit 9, a cross-file race) and PASSES with it.
- Full `npm run test:unit` green with isolation (0 fail; a one-off
  chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated)
  and noticeably faster — the DB lock contention is gone.
- New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when
  unset; explicit DATA_DIR respected).

Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs
+ concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5
unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for
the first cold run before the incremental cache is seeded.

* ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes

The TIA "Impacted unit tests" step (made blocking in #4069) ran its fail-safe via
`npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI
runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g.
`db-backup-extended` "The database connection is not open", `chatcore-translation-paths`
upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly
what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the
__RUN_ALL__ fail-safe.

Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable
ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR
isolation in this PR keeps the parallel run race-free, so the only change here is matching
the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation
(5 with isolation, 3 without).

* docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (#4095)

The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted
9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses`
(lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`,
`check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job).
You can't rationalize an inventory you can't trust, so this reconciles it first.

Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section
capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners
audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api
anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the
operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet,
test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence,
the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the
standalone scanner workflows.

Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are
deferred to operator-scoped follow-ups; this PR only makes the map accurate.

* test(dashboard): smoke e2e for the Combo Live Studio page (#4075)

Integrated into release/v3.8.28

* fix(sse): friendly 413 message for ChatGPT web payload-too-large (#4080)

Integrated into release/v3.8.28

* feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (#4083)

Integrated into release/v3.8.28

* feat(api): exact offline token counting for count_tokens fallback via tiktoken (#4087)

Integrated into release/v3.8.28

* feat(compression): RTK learn/discover (sample source + API + UI) (#4088)

Integrated into release/v3.8.28

* feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (#4089)

Integrated into release/v3.8.28

* feat(mitm): capture-pipeline self-test route (Gap 12) (#4093)

Integrated into release/v3.8.28

* fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (#4084)

Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green)

* feat(mitm): attribute intercepted requests to originating process (Gap 1) (#4085)

Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green)

* fix(sse): route image requests only to confirmed-vision combo targets (#4071)

Integrated into release/v3.8.28

* fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (#4077)

Integrated into release/v3.8.28

* fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (#4079)

Integrated into release/v3.8.28

* fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (#4092)

Integrated into release/v3.8.28

* ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (#4099)

Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk:

1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the
   `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the
   `lint`-job copy was a pure duplicate. No coverage lost.

2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings:
   several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT
   clean drop-ins —
   - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both.
   - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both.
   - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation.
   - complexity + /api merges: valid but real config/script surgery — deferred.
   - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip.

   The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence,
   semgrep) are operator policy decisions, left for the owner.

* chore(deps): bump actions/github-script from 7 to 9 (#4046)

Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved)

* chore(deps): bump actions/setup-node from 4 to 6 (#4048)

Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved)

* chore(deps): bump actions/upload-artifact from 4 to 7 (#4044)

Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved)

* chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (#4047)

Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved)

* deps: bump the development group with 10 updates (#4051)

Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file)

* fix(dashboard): event-driven fail-open auto-refresh for embedded log views (#4054) (#4103)

The Request Logger gated each auto-refresh tick on a static
document.visibilityState === "visible" read. Hosts that report a permanent
non-"visible" state without ever firing a visibilitychange event (Docker
dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely —
only the manual Refresh button worked, a regression from 3.8.24's unconditional
polling.

The pause is now event-driven and fail-open: visibleRef starts true and is only
flipped to false on a real visibilitychange → hidden transition, so a host that
never signals a genuine background transition keeps polling, while normal
browser tabs still pause when actually backgrounded.

Regression test reproduces the misreporting-host case (RED) and the perf guard
is re-encoded under the event-driven semantics.

* fix(docker): raise build-stage Node heap to stop production-build OOM (#4076) (#4104)

The Docker builder stage ran `npm run build` with V8's default heap ceiling
(~2 GB). After #4052 forced the heavier webpack engine (Turbopack panics on this
Next.js version), the production optimization pass exceeded that ceiling and the
build died with "FATAL ERROR: ... JavaScript heap out of memory" at
[builder] npm run build.

The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB,
overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the
value propagates to the spawned next build (resolveNextBuildEnv spreads
process.env). Build-only — the runtime heap on the runner stage is unchanged,
and CI/local builds (which invoke npm run build directly) are unaffected.

Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the
builder stage sets the heap ceiling, before npm run build, at >= 4096 MB.

* feat(agent-bridge): portable JSON import/export of config (Gap 4) (#4094)

Integrated into release/v3.8.28

* feat(cli): add 'omniroute launch' zero-config Claude Code launcher (#4097)

Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from #4084/#4092] + opencode-plugin-dist env flake; #4097 own test 3/3 green)

* feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (#4101)

Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged #4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains)

* feat(sse): generic 400 field-downgrade retry + Groq field stripping (#4096)

Integrated into release/v3.8.28

* feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (#4098)

Integrated into release/v3.8.28

* chore(docs)

* fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (#4105)

Integrated into release/v3.8.28 (r7).

* perf(gemini): cache reasoning close-tag regex instead of recompiling per token (#4106)

Integrated into release/v3.8.28 (r7).

* fix(usage): reap orphaned pending-request details (unbounded memory leak) (#4107)

Integrated into release/v3.8.28 (r7).

* perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (#4108)

Integrated into release/v3.8.28 (r7).

* fix(dashboard): restore Update Available banner with npm-binary-free version fallback (#4100) (#4112)

getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage.

* fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (#4111)

Integrated into release/v3.8.28 (r8)

* fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (#4113)

Integrated into release/v3.8.28 (r8)

* fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (#4114)

Integrated into release/v3.8.28 (r8)

* perf(obfuscation): cache per-word regexes instead of recompiling every request (#4109)

Integrated into release/v3.8.28 (r8)

* perf(registry): precompute model->provider index in parseModelFromRegistry (#4110)

Integrated into release/v3.8.28 (r8)

* fix(timers): unref background interval timers so they don't block clean shutdown (#4117)

Integrated into release/v3.8.28 (r8)

* fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (#4115)

Integrated into release/v3.8.28 (r8)

* fix(combo): detach per-target listener from shared hedge abort signal (#4116)

Integrated into release/v3.8.28 (r8)

* chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract

- Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every
  commit since v3.8.27, grouped by type with PR back-references and human
  contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter,
  Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased].
- Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity).
- Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE
  in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK
  and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync.
- Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when
  the file was relocated this cycle) so docs-sync-strict passes.

* fix(quality): treat test→test renames as relocations, not deletions

The anti-test-masking gate's subcheck-1 collected deleted AND renamed test
files via `--diff-filter=DR --name-only` and flagged every one as "deleted —
human review required", contradicting its own documented contract ("DELETADOS
ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the
test moved, coverage preserved). This false-positived on #4063's legitimate
relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2)
and would block every PR that relocates a test — surfacing only at release-day
because the Fast QG (PR→release) doesn't run test-masking.

The gate now parses `--name-status -M`: true deletions and test→non-test
renames still flag; a test→test rename is run through the assert-reduction
check across the move, so a clean relocation passes while gutting-via-rename
(dropped asserts / new tautologies / skips) still fires. Adds
partitionDeletedRenamed + 6 regression tests.

---------

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Demiurge The Single <megamen932@gmail.com>
Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com>
Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br>
Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com>
Co-authored-by: Rahul sharma <sharmaR0810@gmail.com>
Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com>
Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
2026-06-17 19:26:32 -03:00

36 KiB

omniroute — Agent Guidelines

Project

Unified AI proxy/router — route any LLM through one endpoint. Multi-provider support with 227 provider entries (OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks, Cohere, NVIDIA, Cerebras, Pollinations, Puter, Cloudflare AI, HuggingFace, DeepInfra, SambaNova, Meta Llama API, Moonshot AI, AI21 Labs, Databricks, Snowflake, and many more) with MCP Server (87 tools), A2A v0.3 Protocol, and Electron desktop app.

Live counts (v3.8.24): providers 227 · MCP tools 87 · MCP scopes 30 · A2A skills 6 · open-sse services 115 · routing strategies 15 · auto-combo scoring factors 9 · DB modules 83 · DB migrations 97 · base tables 17 · search providers 11 · i18n locales 42. Refresh with npm run check:docs-all.

Doc Accuracy Discipline (read before writing any doc)

If grep -rn "name" src/ open-sse/ bin/ returns nothing, the name does not exist. Do not document it.

The recurring failure mode in AI-generated docs is plausible-but-unverified specifics. Every claim in a .md file under docs/ should be verifiable against the source.

Rules (enforced by npm run check:fabricated-docs):

  1. Never state an API name, endpoint, path, CLI command, or env var without grepping for it first.
    grep -rn "theName" src/ open-sse/ bin/
    # 0 hits → do not document
    
  2. Never write a line count, file size, migration count, provider count, or strategy count from memory.
    wc -l <file>           # exact line count
    ls <dir>/*.ts | wc -l  # file count
    
  3. Every code example should be copy-pasted from real usage or actually run — not synthesized. Link to a real call site (path:line) instead of inventing a signature.
  4. Prefer citing real source (file.ts:line) over paraphrasing behavior — verifiable and self-correcting.
  5. A shorter doc that is 100% accurate beats a comprehensive one with fabrications. Wrong docs cost more than missing docs, because people trust and act on them.

The script scripts/check/check-fabricated-docs.mjs extracts every route path, env var, hook name, function name, and file reference from docs/**/*.md and verifies each one against the codebase. Run it locally before pushing docs; it runs in CI via npm run check:docs-all.

Stack

  • Runtime: Next.js 16 (App Router), Node.js >=22.0.0 <23 || >=24.0.0 <27, ES Modules ("type": "module")
  • Language: TypeScript 6.0 (src/) + JavaScript (open-sse/, electron/)
  • Database: better-sqlite3 (SQLite) — DATA_DIR configurable, default ~/.omniroute/
  • Streaming: SSE via open-sse internal workspace package
  • Styling: Tailwind CSS v4
  • i18n: next-intl with 42 locales (src/i18n/messages/) — refresh with ls src/i18n/messages/*.json | wc -l
  • Desktop: Electron (cross-platform: Windows, macOS, Linux)
  • Schemas: Zod v4 for all API / MCP input validation

Build, Lint, and Test Commands

Command Description
npm run dev Start Next.js dev server
npm run build Production build: next build.build/next/ + assemble dist/
npm run build:release Clean rebuild + HEAD sentinel (dist/BUILD_SHA) — use for deploy
npm run start Run production build
npm run build:cli Build CLI package
npm run lint ESLint on all source files
npm run typecheck:core TypeScript core type checking
npm run typecheck:noimplicit:core Strict checking (no implicit any)
npm run check Run lint + test
npm run check:cycles Check for circular dependencies
npm run electron:dev Run Electron app in dev mode
npm run electron:build Build Electron app for current OS

Build output layout:

Directory Purpose Gitignored
src/ Application source (TypeScript / TSX) No
.build/ Build intermediates (distDir = .build/next) Yes
dist/ Shippable bundle assembled by assembleStandalone Yes

The pipeline is a single next build pass — intermediates land in .build/next/, the assembled bundle in dist/. VPS deploys rsync dist/ into the remote /usr/lib/node_modules/omniroute/app/ directory (VPS image path is unchanged).

Running Tests

# All tests (unit + vitest + ecosystem + e2e)
npm run test:all

# Single test file (Node.js native test runner — most tests use this)
node --import tsx/esm --test tests/unit/your-file.test.ts
node --import tsx/esm --test tests/unit/plan3-p0.test.ts
node --import tsx/esm --test tests/unit/fixes-p1.test.ts
node --import tsx/esm --test tests/unit/security-fase01.test.ts

# Integration tests
node --import tsx/esm --test tests/integration/*.test.ts

# Vitest (MCP server, autoCombo)
npm run test:vitest

# E2E with Playwright
npm run test:e2e

# Protocol clients E2E (MCP transports, A2A)
npm run test:protocols:e2e

# Ecosystem compatibility tests
npm run test:ecosystem

# Coverage (see CONTRIBUTING.md)
npm run test:coverage

For authoritative coverage requirements, test execution, and PR gates, see CONTRIBUTING.md.


Code Style Guidelines

Formatting (Prettier — enforced via lint-staged)

2 spaces · semicolons required · double quotes (") · 100 char width · es5 trailing commas. Always run prettier --write on changed files.

TypeScript

  • Target: ES2022 · Module: esnext · Resolution: bundler
  • strict: false — prefer explicit types, don't rely on inference
  • Path aliases: @/*src/, @omniroute/open-sseopen-sse/, @omniroute/open-sse/*open-sse/*

ESLint Rules

  • Security (error, everywhere): no-eval, no-implied-eval, no-new-func
  • Relaxed in open-sse/ and tests/: @typescript-eslint/no-explicit-any = warn
  • React hooks rules and @next/next/no-assign-module-variable disabled in open-sse/ and tests/

Naming

Element Convention Example
Files camelCase / kebab-case chatCore.ts, tokenHealthCheck.ts
React components PascalCase Dashboard.tsx, ProviderCard.tsx
Functions/variables camelCase getHealth(), switchCombo()
Constants UPPER_SNAKE MAX_RETRIES, DEFAULT_TIMEOUT
Interfaces PascalCase (I prefix optional) ProviderConfig
Enums PascalCase (members too) LogLevel.Error

Imports

  • Order: external → internal (@/, @omniroute/open-sse) → relative (./, ../)
  • No barrel imports from localDb.ts — import from the specific db/ module instead

Error Handling

  • try/catch with specific error types; always log with context (pino logger)
  • Never silently swallow errors in SSE streams — use abort signals for cleanup
  • Return proper HTTP status codes (4xx client, 5xx server)

Security

  • NEVER commit API keys, secrets, or credentials
  • Validate all user inputs with Zod schemas
  • Auth middleware required on all API routes
  • Never log SQLite encryption keys
  • Sanitize user content (dompurify for HTML)
  • Public upstream OAuth identifiers (Gemini / Antigravity / Windsurf-style client_id/secret + Firebase Web keys extracted from public CLIs): use resolvePublicCred() from open-sse/utils/publicCreds.ts, never as string literals. Full pattern in docs/security/PUBLIC_CREDS.md.
  • Error responses (HTTP / SSE / executor / MCP): use buildErrorBody() or sanitizeErrorMessage() from open-sse/utils/error.ts, never put raw err.stack / err.message in a Response body. Full pattern in docs/security/ERROR_SANITIZATION.md.
  • exec() / spawn() with runtime values: pass via the env option, never string-interpolate paths/values into the script body. Reference: src/mitm/cert/install.ts::updateNssDatabases.
  • Prefer secure-by-default libraries when available — see tldrsec/awesome-secure-defaults for the curated list (Helmet.js, DOMPurify, ssrf-req-filter, safe-regex, Google Tink, etc.).

Architecture

Data Layer (src/lib/db/)

All persistence uses SQLite through 83 domain-specific modules in src/lib/db/. Top modules:

  • Core: core.ts, migrationRunner.ts, encryption.ts, stateReset.ts
  • Providers / catalog: providers.ts, models.ts, providerLimits.ts, compressionAnalytics.ts
  • Routing: combos.ts, modelComboMappings.ts, domainState.ts, commandCodeAuth.ts
  • Auth: apiKeys.ts, secrets.ts, registeredKeys.ts, sessionAccountAffinity.ts
  • Usage / billing: quotaSnapshots.ts, creditBalance.ts, usage*.ts, compressionCacheStats.ts
  • Storage: backup.ts, cleanup.ts, jsonMigration.ts, healthCheck.ts, databaseSettings.ts
  • Extension modules: evals.ts, webhooks.ts, reasoningCache.ts, readCache.ts, tierConfig.ts, compressionCombos.ts, compressionScheduler.ts, batches.ts, files.ts, syncTokens.ts, proxies.ts, oneproxy.ts, upstreamProxy.ts, versionManager.ts, cliToolState.ts, prompts.ts, detailedLogs.ts, contextHandoffs.ts, compression.ts, stats.ts

Live count: ls src/lib/db/*.ts | wc -l (currently 83). Drift detection: npm run check:docs-counts. Schema migrations live in db/migrations/ (97 files as of v3.8.24) and run via migrationRunner.ts. src/lib/localDb.ts is a re-export layer only — never add logic there.

DB Internals

  • core.ts: getDbInstance() returns a singleton better-sqlite3 instance with WAL journaling. SCHEMA_SQL defines 17 base tables (verify with grep -c "CREATE TABLE" src/lib/db/core.ts minus 1 for the bookkeeping _omniroute_migrations table). Helpers: rowToCamel, encryptConnectionFields.
  • migrationRunner.ts: Applies versioned SQL files from db/migrations/ inside transactions. Tracks applied migrations in _omniroute_migrations table.
  • Migrations: 97 files (001_initial_schema.sql099_*.sql). Each migration is idempotent and runs in a transaction. Live count: ls src/lib/db/migrations/*.sql | wc -l.
  • Domain modules import getDbInstance() from core.ts for all CRUD operations. Each module owns a specific table/set of tables (e.g., providers.tsprovider_connections, combos.tscombos). Encryption helpers protect sensitive fields at rest.
  • localDb.ts re-exports all domain modules — consumers import from here for convenience.

API Route Layer (src/app/api/v1/)

Next.js App Router routes — each follows a consistent pattern:

Route → CORS preflight → Body validation (Zod) → Optional auth (extractApiKey/isValidApiKey)
  → API key policy enforcement (enforceApiKeyPolicy) → Handler delegation (open-sse)
Route Handler Notes
chat/completions/route.ts handleChat() + prompt injection guard (clones request)
responses/route.ts handleChat() (unified) Responses API format
embeddings/route.ts handleEmbedding() Model listing + creation
images/generations/route.ts handleImageGeneration() Model listing + creation
audio/transcriptions/route.ts audio handler Multipart form data
audio/speech/route.ts TTS handler Binary audio response
videos/generations/route.ts video handler ComfyUI/SD WebUI
music/generations/route.ts music handler ComfyUI workflows
moderations/route.ts moderation handler Content safety
rerank/route.ts rerank handler Document relevance
search/route.ts search handler Web search (12 providers per open-sse/handlers/search.ts:6)

No global Next.js middleware file — interception is route-specific. Auth is optional (controlled by REQUIRE_API_KEY env). Prompt injection guard is unique to chat completions.

Request Pipeline (open-sse/)

The open-sse/ workspace is the core streaming engine. Full request flow:

Client Request
  → src/app/api/v1/.../route.ts (Next.js route)
    → open-sse/handlers/chatCore.ts::handleChatCore()
      → Semantic/signature cache check
      → Rate limit check (rateLimitManager)
      → Combo routing? → open-sse/services/combo.ts::handleComboChat()
        → resolveComboTargets() → ordered ResolvedComboTarget[]
        → For each target: handleSingleModel() (wraps chatCore)
      → translateRequest() (open-sse/translator/)
        → Convert source format (e.g., OpenAI) → target format (e.g., Claude)
      → getExecutor() → provider-specific executor instance
        → executor.execute() (BaseExecutor → DefaultExecutor or provider-specific)
          → buildUrl() + buildHeaders() + transformRequest()
          → fetch() to upstream provider
          → Retry logic with exponential backoff
      → Response translation back to client format
      → If Responses API: responsesTransformer.ts TransformStream
  → SSE stream or JSON response to client

Handlers (open-sse/handlers/): chatCore.ts, responsesHandler.ts, embeddings.ts, imageGeneration.ts, videoGeneration.ts, musicGeneration.ts, audioSpeech.ts, audioTranscription.ts, moderations.ts, rerank.ts, search.ts.

Upstream headers: merged after default auth; same header name replaces executor value. T5 intra-family fallback recomputes headers using only the fallback model id. Forbidden header names: src/shared/constants/upstreamHeaders.ts — keep sanitize, Zod schemas, and unit tests aligned when editing.

Provider Categories

  • Free (4): Qoder AI, Qwen Code, Gemini CLI (deprecated), Kiro AI
  • OAuth (14): Claude Code, Antigravity, Codex, GitHub Copilot, Cursor, Kimi Coding, Kilo Code, Cline, Qwen (⚠️ free tier discontinued 2026-04-15), Kiro, Qoder, Gemini, Windsurf (v3.8), GitLab Duo (v3.8)
  • API Key (120+): OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Perplexity, Together, Fireworks, Cerebras, Cohere, NVIDIA, Nebius, SiliconFlow, Hyperbolic, HuggingFace, OpenRouter, Vertex AI, Cloudflare AI, Scaleway, AI/ML API, Pollinations, Puter, Longcat, Alibaba, Kimi, Minimax, Blackbox, Synthetic, Kilo Gateway, Z.AI, GLM, Deepgram, AssemblyAI, ElevenLabs, Cartesia, PlayHT, Inworld, NanoBanana, SD WebUI, ComfyUI, Ollama Cloud, Perplexity Search, Serper, Brave, Exa, Tavily, OpenCode Zen/Go, Bailian Coding Plan, DeepInfra, Vercel AI Gateway, Lambda AI, SambaNova, nScale, OVHcloud AI, Baseten, PublicAI, Moonshot AI, Meta Llama API, v0 (Vercel), Morph, Featherless AI, FriendliAI, LlamaGate, Galadriel, Weights & Biases Inference, Volcengine, AI21 Labs, Venice.ai, Codestral, Upstage, Maritalk, Xiaomi MiMo, Inference.net, NanoGPT, Predibase, Bytez, Heroku AI, Databricks, Snowflake Cortex, GigaChat (Sber), CrofAI, AgentRouter, ChatGPT Web, Baidu Qianfan, AWS Polly, RunwayML, GitLab Duo, Amazon Q, Empower, Poe, and many more.
  • Self-Hosted (8+): LM Studio, vLLM, Lemonade, Llamafile, Triton, Docker Model Runner, Xinference, Oobabooga
  • Custom: OpenAI-compatible (openai-compatible-*) and Anthropic-compatible (anthropic-compatible-*) prefixes

Providers are registered in src/shared/constants/providers.ts with Zod validation at module load.

Executors (open-sse/executors/)

Provider-specific request executors: base.ts, default.ts, cursor.ts, codex.ts, antigravity.ts, github.ts, gemini-cli.ts, kiro.ts, qoder.ts, vertex.ts, cloudflare-ai.ts, opencode.ts, pollinations.ts, puter.ts.

Executor Internals

  • base.ts (BaseExecutor): Abstract base with buildUrl(), buildHeaders(), transformRequest(), retry logic (exponential backoff), and execute(). Subclasses override URL/header/transform methods for provider-specific behavior.
  • default.ts (DefaultExecutor extends BaseExecutor): Handles most OpenAI-compatible providers. Reads provider config from providerRegistry.ts to resolve base URL, auth header format, and request transformations.
  • getExecutor() (executors/index.ts): Factory that returns the correct executor instance based on provider ID. Provider-specific executors (Cursor, Codex, Vertex, etc.) override only what differs from the default.

Translator (open-sse/translator/)

Translates between API formats (OpenAI-format ↔ Anthropic, Gemini, etc.). Includes request/response translators with helpers for image handling.

Translator Internals

  • translator/index.ts: Exports translateRequest() and format constants. Called by chatCore.ts before executor dispatch.
  • Flow: translateRequest(body, sourceFormat, targetFormat) → detects source format (OpenAI, Anthropic, Gemini) → applies the matching translator module → returns transformed body ready for the target provider.
  • Response translation runs in reverse after upstream response, converting back to the client's expected format.

Transformer (open-sse/transformer/)

responsesTransformer.ts — transforms Responses API format to/from Chat Completions format.

Transformer Internals

  • createResponsesApiTransformStream(): Returns a TransformStream that converts Chat Completions SSE chunks (data: {"choices":[...]}) into Responses API SSE events (response.output_item.added, response.output_text.delta, etc.).
  • Used when the client sends a Responses API request: the request is internally converted to Chat Completions format, dispatched normally, and the response is piped through this transform stream before reaching the client.

Services (open-sse/services/)

115 service modules in open-sse/services/ (top-level only; 184 including sub-dirs like autoCombo/ and compression/). Refresh: ls open-sse/services/*.ts | wc -l. Key modules: combo.ts (routing engine), usage.ts, tokenRefresh.ts, rateLimitManager.ts, accountFallback.ts, sessionManager.ts, wildcardRouter.ts, autoCombo/, intentClassifier.ts, taskAwareRouter.ts, thinkingBudget.ts, contextManager.ts, modelDeprecation.ts, modelFamilyFallback.ts, emergencyFallback.ts, workflowFSM.ts, backgroundTaskDetector.ts, ipFilter.ts, signatureCache.ts, volumeDetector.ts, contextHandoff.ts, compression/ (prompt compression pipeline), and more.

Prompt Compression Pipeline (compression/)

Modular prompt compression that runs proactively before the existing reactive context manager.

  • strategySelector.ts: Selects compression mode based on config, compression combo assignments, combo overrides, auto-trigger thresholds, and defaults. Priority: assigned compression combo > combo override > auto-trigger > default mode > off.
  • lite.ts: 5 lite-mode techniques: collapseWhitespace, dedupSystemPrompt, compressToolResults, removeRedundantContent, replaceImageUrls. Target: 10-15% savings at <1ms latency.
  • caveman.ts / cavemanRules.ts: Caveman-style semantic condensation backed by built-in rules plus file-loaded language packs under compression/rules/.
  • engines/rtk/: Rule-based terminal/tool-output compression inspired by RTK patterns. Detects command output classes, applies JSON filter packs, deduplicates repeated lines, strips ANSI/code noise, and preserves errors/actionable context. The RTK JSON DSL supports replace, match-output short-circuit, strip/keep, per-line truncation, head/tail/max-line truncation, inline tests, trust-gated project/global custom filters, and optional redacted raw-output retention for authenticated recovery.
  • engines/registry.ts: Registers engines (caveman, rtk) and powers stacked pipelines.
  • stats.ts: Per-request compression stats tracking (original tokens, compressed tokens, savings %, techniques used, engine breakdown, compression combo id).
  • types.ts: CompressionMode (off/lite/standard/aggressive/ultra/rtk/stacked), CompressionConfig, CompressionStats, CompressionResult.
  • DB settings in src/lib/db/compression.ts, compression combos in src/lib/db/compressionCombos.ts, API routes under src/app/api/settings/compression/, src/app/api/context/*, and preview/language-pack routes under src/app/api/compression/*.

Combo Routing Engine (combo.ts)

  • handleComboChat(): Entry point for combo-routed requests. Receives the combo config and iterates through targets in order until one succeeds or all fail.
  • resolveComboTargets(): Expands a combo configuration into an ordered array of ResolvedComboTarget[], each specifying provider + model + account + credentials.
  • Strategies (15): priority, weighted, fill-first, round-robin, P2C, random, least-used, reset-aware (v3.8), reset-window, cost-optimized, strict-random, auto, lkgp, context-optimized, context-relay. Source: ROUTING_STRATEGY_VALUES in src/shared/constants/routingStrategies.ts.
  • Each target calls handleSingleModel() which wraps handleChatCore() with per-target error handling and circuit breaker checks.

Domain Layer (src/domain/)

Policy engine modules: policyEngine.ts, comboResolver.ts, costRules.ts, degradation.ts, fallbackPolicy.ts, lockoutPolicy.ts, modelAvailability.ts, providerExpiration.ts, quotaCache.ts, responses.ts, configAudit.ts.

MCP Server (open-sse/mcp-server/)

87 tools total (TOTAL_MCP_TOOL_COUNT, open-sse/mcp-server/server.ts): a 33-entry base registry (MCP_TOOLS in schemas/tools.ts, bundling the core / cache / compression / 1proxy / advanced tools) plus standalone module sets — memory (3), skill (4), agentSkill (3), gamification (8), plugin (8), notion (6), obsidian (22). 3 transports (stdio / SSE / Streamable HTTP). Scoped auth (30 scopes — see OMNIROUTE_MCP_SCOPES), Zod schemas. See docs/frameworks/MCP-SERVER.md.

Core tools (20): get_health, list_combos, get_combo_metrics, switch_combo, check_quota, route_request, cost_report, list_models_catalog, web_search, simulate_route, set_budget_guard, set_routing_strategy, set_resilience_profile, test_combo, get_provider_metrics, best_combo_for_task, explain_route, get_session_snapshot, db_health_check, sync_pricing.

Cache tools (2): cache_stats, cache_flush.

Compression tools (5): compression_status, compression_configure, set_compression_engine, list_compression_combos, compression_combo_stats.

1proxy tools (3): oneproxy_fetch, oneproxy_rotate, oneproxy_stats.

Memory tools (3): memory_search, memory_add, memory_clear.

Skill tools (4): skills_list, skills_enable, skills_execute, skills_executions.

Agent-skill tools (3): A2A skill discovery / invocation bridges.

Gamification tools (8): levels, badges, leaderboard, and community-federation queries.

Plugin tools (8): plugin marketplace listing, install/enable/disable, and runtime inspection.

Notion tools (6) + Obsidian tools (22): knowledge-base read/write integrations (the largest tool family — vault search, note CRUD, WebDAV-backed file ops).

MCP Internals

  • Tool registration: Each tool is an object with { name, description, inputSchema: ZodSchema, handler: async (args) => {...} }. Zod validates inputs before the handler fires.
  • createMcpServer() and startMcpStdio() exported from mcp-server/index.ts. createMcpServer() wires all tool sets; startMcpStdio() launches the stdio transport.
  • Transports: stdio (CLI omniroute --mcp), SSE (/api/mcp/sse), Streamable HTTP (/api/mcp/stream). All share the same tool/scope engine.
  • Scopes (30): Control which tool categories an API key can access. Enforcement happens before handler dispatch.
  • Audit: Every tool invocation is logged to SQLite (mcp_audit table) with tool name, args, success/failure, API key attribution, and timestamp.

A2A Server (src/lib/a2a/)

JSON-RPC 2.0, SSE streaming, Task Manager with TTL cleanup. Agent Card at /.well-known/agent.json. Skills (6): smartRouting.ts, quotaManagement.ts, providerDiscovery.ts, costAnalysis.ts, healthReport.ts, listCapabilities.ts.

A2A Internals

  • taskManager.ts: State machine lifecycle for tasks: submitted → working → completed | failed | canceled. Tasks have TTL and are cleaned up automatically.
  • JSON-RPC methods: message/send (sync), message/stream (SSE), tasks/get, tasks/cancel. Dispatched via POST /a2a.
  • Skills: Registered in a DB-backed registry. Each skill receives task context (messages, metadata) and returns structured results. quotaManagement.ts summarizes quota; smartRouting.ts recommends routing decisions.
  • Agent Card: /.well-known/agent.json exposes capabilities, skills, and metadata for client auto-discovery.

ACP Module (src/lib/acp/)

Agent Communication Protocol registry and manager.

Memory System (src/lib/memory/)

Extraction, injection, retrieval, summarization, and store modules for persistent conversational memory across sessions.

Skills System (src/lib/skills/)

Extensible skill framework: registry, executor, sandbox, built-in skills, custom skill support, interception, and injection.

Skills Internals

  • registry.ts: DB-backed skill registration and discovery. Skills have metadata (name, description, version, enabled status) stored in SQLite.
  • executor.ts: Execution engine with configurable timeout and retry logic. Receives skill name + input, looks up the skill, runs it in the sandbox.
  • sandbox.ts: Isolation layer for custom (user-provided) skills. Limits resource access and execution time.
  • Built-in skills: Ship with OmniRoute (e.g., quota management, routing). Located alongside the registry.
  • Interception/Injection: Skills can intercept requests in the pipeline (pre/post processing) or inject context into prompts.

Compliance (src/lib/compliance/)

Policy index for compliance enforcement.

MITM Proxy (src/mitm/)

MITM proxy capability with certificate management, DNS handling, and target routing.

Middleware (src/middleware/)

Request middleware including promptInjectionGuard.ts.

Guardrails (src/lib/guardrails/)

Hot-reloadable guardrails framework (3 built-in: pii-masker, prompt-injection, vision-bridge). Fail-open; per-request opt-out via header. See docs/security/GUARDRAILS.md.

Cloud Agents (src/lib/cloudAgent/)

CloudAgentBase abstract class + 3 agents (codex-cloud, devin, jules). Tasks persisted in cloud_agent_tasks; management auth required. See docs/frameworks/CLOUD_AGENT.md.

Evals (src/lib/evals/)

Generic eval framework: evalRunner.ts, runtime.ts. Targets: combo / model / suite-default. See docs/frameworks/EVALS.md.

Webhooks (src/lib/webhookDispatcher.ts)

HMAC-signed delivery, exponential backoff, auto-disable after 10 failures. 7 event types. See docs/frameworks/WEBHOOKS.md.

Authorization Pipeline (src/server/authz/)

classify → policies → enforce. 3 route classes (PUBLIC / CLIENT_API / MANAGEMENT). See docs/architecture/AUTHZ_GUIDE.md.

Reasoning Replay (src/lib/db/reasoningCache.ts + open-sse/services/reasoningCache.ts)

Hybrid in-memory + SQLite cache for reasoning_content. Re-injects on multi-turn for strict providers (DeepSeek V4, Kimi K2, Qwen-Thinking, GLM, xiaomi-mimo). See docs/routing/REASONING_REPLAY.md.

Tunnels (src/lib/{cloudflaredTunnel,ngrokTunnel}.ts + src/app/api/tunnels/)

Cloudflare Quick/Named, ngrok, Tailscale Funnel. See docs/ops/TUNNELS_GUIDE.md.

Adding a New Provider

  1. Register in src/shared/constants/providers.ts
  2. Add executor in open-sse/executors/ (if custom logic needed)
  3. Add translator in open-sse/translator/ (if non-OpenAI format)
  4. Add OAuth config in src/lib/oauth/constants/oauth.ts (if OAuth-based)
  5. Add models in open-sse/config/providerRegistry.ts

Subdirectory AGENTS.md Files

Reference Documentation (docs/)

For any non-trivial change, read the matching deep-dive first:

Area Doc
Repo navigation docs/architecture/REPOSITORY_MAP.md
Architecture docs/architecture/ARCHITECTURE.md
Engineering reference docs/architecture/CODEBASE_DOCUMENTATION.md
Auto-Combo (12-factor, 15 strategies) docs/routing/AUTO-COMBO.md
Resilience (3 layers) docs/architecture/RESILIENCE_GUIDE.md
Skills docs/frameworks/SKILLS.md
Memory docs/frameworks/MEMORY.md
Cloud agents docs/frameworks/CLOUD_AGENT.md
Guardrails docs/security/GUARDRAILS.md
Evals docs/frameworks/EVALS.md
Compliance docs/security/COMPLIANCE.md
Webhooks docs/frameworks/WEBHOOKS.md
Authz docs/architecture/AUTHZ_GUIDE.md
Stealth docs/security/STEALTH_GUIDE.md
Reasoning replay docs/routing/REASONING_REPLAY.md
Agent protocols (A2A / ACP / Cloud) docs/frameworks/AGENT_PROTOCOLS_GUIDE.md
MCP server docs/frameworks/MCP-SERVER.md
A2A server docs/frameworks/A2A-SERVER.md
API reference docs/reference/API_REFERENCE.md + docs/reference/openapi.yaml
Provider catalog (auto-generated) docs/reference/PROVIDER_REFERENCE.md
Tunnels docs/ops/TUNNELS_GUIDE.md
Electron desktop docs/guides/ELECTRON_GUIDE.md
Release flow docs/ops/RELEASE_CHECKLIST.md
Quality gates (35 gates, allowlist policy) docs/architecture/QUALITY_GATES.md

Fork / Upstream Workflow

This repository is a fork of diegosouzapw/OmniRoute. Keep fork-only operational changes (for example GHCR image publishing, personal deployment workflows, or local automation) out of upstream contribution PRs.

When preparing a PR for upstream, always start the work branch from upstream/main, not from this fork's main:

git fetch upstream
git switch -c <branch-name> upstream/main

Only cherry-pick or reapply the changes intended for the upstream PR.


Review Focus

  • DB ops go through src/lib/db/ modules, never raw SQL in routes
  • Provider requests flow through open-sse/handlers/
  • MCP/A2A pages are tabs inside /dashboard/endpoint, not standalone routes
  • No memory leaks in SSE streams (abort signals, cleanup)
  • Rate limit headers must be parsed correctly
  • All API inputs validated with Zod schemas
  • Provider constants validated at module load via Zod (src/shared/validation/providerSchema.ts)
  • Pricing data syncs from LiteLLM via src/lib/pricingSync.ts
  • Memory/Skills are cross-cutting: affect MCP tools, request pipeline, and A2A skills
  • NEVER close a contributor's PR after using their code — always merge via GitHub so they get credit. See .agents/workflows/review-prs.md for full policy.