Skip to content

feat(services): add Mux managed embedded service - #6034

Merged
diegosouzapw merged 2 commits into
release/v3.8.44from
feat/port-pr-1802-mux-service
Jul 3, 2026
Merged

diegosouzapw merged 2 commits into
release/v3.8.44from
feat/port-pr-1802-mux-service

Conversation

@diegosouzapw

@diegosouzapw diegosouzapw commented Jul 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds Mux (coder/mux — a local agent-orchestration daemon) as a fourth managed
embedded service, built entirely on the existing ServiceSupervisor framework
(the same shape as ninerouter and CLIProxyAPI) rather than a bespoke integration.

Thanks to @Ansh7473 for the original implementation.

Install method chosen: npm (not git-clone+build)

mux is published on npm (npm view mux → mux@0.27.0, bin: mux -> dist/cli/index.js)
with a documented headless mode: mux server --host <host> --port <port>. Since an
npm-installable path exists, the installer uses the existing runNpm helper
(src/lib/services/installers/utils.ts) exactly like the ninerouter installer — no
git-clone+build capability was introduced.

Server details verified by inspecting the published tarball (npm pack mux@0.27.0):

  • GET /health → { status: "ok" } (used as the supervisor health-check path)
  • Auth: --auth-token <token> flag or MUX_SERVER_AUTH_TOKEN env var
  • Home dir override: MUX_ROOT env var (scoped under DATA_DIR/services/mux/data
    instead of leaking into ~/.mux)

What changed

  • src/lib/services/installers/mux.ts — npm install/update, resolveSpawnArgs()
  • src/lib/services/bootstrap.ts — registered in SERVICES[]
  • src/lib/db/migrations/113_mux_service_seed.sql — version_manager seed row
  • src/app/api/services/mux/{install,start,stop,restart,update,status,auto-start} —
    7 endpoints, all delegating errors through createErrorResponse()
  • src/app/api/services/[name]/logs/route.ts — wired mux into the shared SSE logs dispatcher
  • src/app/(dashboard)/dashboard/providers/services/tabs/MuxServiceTab.tsx — dashboard tab
    reusing ServiceStatusCard, ServiceLifecycleButtons, AutoStartToggle, ServiceLogsPanel
  • docs/frameworks/EMBEDDED-SERVICES.md, docs/openapi.yaml, docs/reference/ENVIRONMENT.md,
    .env.example — documentation updates

Security

  • Hard Rule fix(ci): explicit .npmrc auth for npm publish #17 (loopback gating): every /api/services/mux/* route is already
    covered by the existing LOCAL_ONLY_API_PREFIXES "/api/services/" prefix in
    src/server/authz/routeGuard.ts. Added an explicit regression test asserting
    isLocalOnlyPath() returns true for all 8 mux routes
    (tests/unit/authz/routeGuard.test.ts).
  • Mux always binds to 127.0.0.1 explicitly (never 0.0.0.0) as defense-in-depth,
    since it orchestrates AI agents capable of executing host commands.
  • Hard Rule deps: bump qs from 6.14.1 to 6.14.2 #13 (no shell interpolation): the installer uses runNpm (array args,
    install prefix via the env option) — identical safety contract to the ninerouter
    installer. resolveSpawnArgs() also uses array args, never shell-interpolated
    strings.
  • The bearer token is generated the same way as ninerouter's key (getOrCreateApiKey)
    and injected via MUX_SERVER_AUTH_TOKEN (mux's documented env form) — never as a
    CLI flag, so it never appears in ps/process listings.
  • Hard Rule fix(ui): fix Select dropdown dark theme inconsistency #12: all route errors go through createErrorResponse() /
    sanitizeErrorMessage().

Test plan

  • node --import tsx/esm --test tests/unit/services/installers/mux.test.ts — 9/9 pass
  • node --import tsx/esm --test tests/unit/authz/routeGuard.test.ts — 31/31 pass (incl. new mux loopback-gating assertions)
  • node --import tsx/esm --test tests/unit/dashboard/providers/services/mux-tab.test.ts — 1/1 pass
  • node --import tsx/esm --test tests/unit/check-route-guard-membership.test.ts — 15/15 pass
  • Full isolated-DATA_DIR sweep (tests/unit/services/**, tests/unit/authz/**,
    tests/unit/dashboard/providers/services/**) — 511/511 pass
  • npm run typecheck:core — clean
  • npm run check:cycles — no cycles
  • npm run check:docs-all — pass (env/docs contract in sync)
  • npm run check:openapi-coverage / check:openapi-routes / check:openapi-security-tiers — pass
  • npm run check:any-budget:t11 / check:tracked-artifacts — pass
  • npx eslint on all changed/new files — 0 errors (1 pre-existing warning, unrelated line)

Adds Mux (coder/mux — local agent-orchestration daemon) as a fourth-tier
embedded service built on the existing ServiceSupervisor framework, the
same shape as 9Router and CLIProxyAPI:

- Installer (src/lib/services/installers/mux.ts): npm install/update via
  runNpm (array args + env-based prefix, no shell interpolation), modeled
  on ninerouter.ts. Mux ships an npm package (`mux`) with a documented
  headless `mux server --host <host> --port <port>` mode, so no
  git-clone+build path was needed.
- Registered in bootstrap.ts (SERVICES[] + buildSpawnArgsFactory).
- DB seed migration 113 (version_manager row, not_installed/auto_start=0).
- 7 API endpoints under /api/services/mux/ (install/start/stop/restart/
  update/status/auto-start) plus the shared [name]/logs SSE endpoint,
  mirroring the cliproxy route shape and delegating errors through
  createErrorResponse().
- Dashboard tab (MuxServiceTab) reusing ServiceStatusCard,
  ServiceLifecycleButtons, AutoStartToggle, ServiceLogsPanel.
- Docs: EMBEDDED-SERVICES.md (service table, architecture diagram, API
  reference, key-injection section), openapi.yaml, ENVIRONMENT.md,
  .env.example.

Security:
- Every /api/services/mux/* route is covered by the existing
  LOCAL_ONLY_API_PREFIXES "/api/services/" prefix (Hard Rule #17);
  added an explicit isLocalOnlyPath regression test for all 8 routes.
- Mux binds to 127.0.0.1 explicitly (never 0.0.0.0) as defense-in-depth,
  since it orchestrates AI agents that can execute host commands.
- The bearer token is generated the same way as 9Router's key
  (getOrCreateApiKey) and injected via MUX_SERVER_AUTH_TOKEN (mux's
  documented env form) rather than a CLI flag, so it never appears in
  `ps`/process listings.
- No shell interpolation anywhere in the installer (Hard Rule #13): all
  npm/spawn args are static arrays; the install prefix and auth token
  travel via the env option.

Co-authored-by: Ansh7473 <Ansh7473@users.noreply.github.com>
Inspired-by: decolua/9router#1802
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

KooshaPari added a commit to KooshaPari/OmniRoute that referenced this pull request Jul 3, 2026
…pw#6034) (#254)

Co-authored-by: Ansh7473 <Ansh7473@users.noreply.github.com>
@KooshaPari

Copy link
Copy Markdown
Contributor

@diegosouzapw
diegosouzapw merged commit dc7892c into release/v3.8.44 Jul 3, 2026
1 of 3 checks passed
@diegosouzapw
diegosouzapw deleted the feat/port-pr-1802-mux-service branch July 3, 2026 12:12
@diegosouzapw diegosouzapw mentioned this pull request Jul 4, 2026
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
Adds Mux (coder/mux — local agent-orchestration daemon) as a fourth-tier
embedded service built on the existing ServiceSupervisor framework, the
same shape as 9Router and CLIProxyAPI:

- Installer (src/lib/services/installers/mux.ts): npm install/update via
  runNpm (array args + env-based prefix, no shell interpolation), modeled
  on ninerouter.ts. Mux ships an npm package (`mux`) with a documented
  headless `mux server --host <host> --port <port>` mode, so no
  git-clone+build path was needed.
- Registered in bootstrap.ts (SERVICES[] + buildSpawnArgsFactory).
- DB seed migration 113 (version_manager row, not_installed/auto_start=0).
- 7 API endpoints under /api/services/mux/ (install/start/stop/restart/
  update/status/auto-start) plus the shared [name]/logs SSE endpoint,
  mirroring the cliproxy route shape and delegating errors through
  createErrorResponse().
- Dashboard tab (MuxServiceTab) reusing ServiceStatusCard,
  ServiceLifecycleButtons, AutoStartToggle, ServiceLogsPanel.
- Docs: EMBEDDED-SERVICES.md (service table, architecture diagram, API
  reference, key-injection section), openapi.yaml, ENVIRONMENT.md,
  .env.example.

Security:
- Every /api/services/mux/* route is covered by the existing
  LOCAL_ONLY_API_PREFIXES "/api/services/" prefix (Hard Rule diegosouzapw#17);
  added an explicit isLocalOnlyPath regression test for all 8 routes.
- Mux binds to 127.0.0.1 explicitly (never 0.0.0.0) as defense-in-depth,
  since it orchestrates AI agents that can execute host commands.
- The bearer token is generated the same way as 9Router's key
  (getOrCreateApiKey) and injected via MUX_SERVER_AUTH_TOKEN (mux's
  documented env form) rather than a CLI flag, so it never appears in
  `ps`/process listings.
- No shell interpolation anywhere in the installer (Hard Rule diegosouzapw#13): all
  npm/spawn args are static arrays; the install prefix and auth token
  travel via the env option.


Inspired-by: decolua/9router#1802

Co-authored-by: Ansh7473 <Ansh7473@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants