SterlingIndex Docs

Packages and Contracts

Shared package ownership, consumer map, and the contracts that connect the frontend apps to the platform API.

SterlingIndex keeps its reusable frontend-to-backend seams intentionally small. The shared packages in packages/* are not a grab bag of helpers; each one owns a specific boundary that multiple applications depend on.

One recent example of that design choice: observability is intentionally app-local. Sentry and PostHog setup now lives inside the frontend apps that use them (apps/www, apps/dashboard, apps/admin-desktop, and the reference apps/legacy-admin), not in packages/*, because release names, identity rules, sampling, and privacy boundaries differ by surface.

Package Map

PackageOwnsPrimary exportsMajor consumersArchitectural boundary
@sterling/authLogin/logout URL construction and return-to propagationnormalizeBaseUrl, withReturnTo, buildDashboardLoginHref, buildPlatformLoginHref, buildPlatformLogoutHrefapps/www/src/lib/marketing.ts, apps/docs/src/lib/layout-options.tsxKeeps marketing, docs, dashboard, and platform auth redirects aligned without duplicating URL logic.
@sterling/contractsShared TypeScript response and domain shapesSessionResponse, DashboardBootstrapResponse, Attorney, Firm, NewsItem, SavedList, search result types, assistant conversation types@sterling/data-client, dashboard contexts/pages, admin auth gateDefines the compile-time data contract that frontend code expects from the product API.
@sterling/data-clientBrowser-facing API adapter for the product surfacerequestJson, buildPlatformUrl, session helpers, dashboard bootstrap/search/news/list APIs, assistant streaming helpersapps/dashboard/src/context/*, apps/dashboard/src/pages/LoginPage.tsx, apps/dashboard/src/pages/AiAssistantPage.tsxGives the dashboard a stable transport layer to /v1/* endpoints on the platform API.
@sterling/admin-runtimeLocal operator runtime supervision and control-plane adapter codeenv parsing/redaction, secure env cache, runtime manager, control-plane client, snapshot package builderapps/admin-mcp now; apps/admin-desktop can adopt the shared pieces laterKeeps MCP and Electron-style operator adapters aligned without moving scraper logic out of services/platform-api.
packages/configShared TypeScript compiler policytsconfig.base.jsonapps/admin-desktop/tsconfig.renderer.json, apps/legacy-admin/tsconfig.json, services/platform-api/apps/web/tsconfig.jsonCentralizes frontend TS defaults without becoming a runtime dependency.

@sterling/auth: Cross-App Auth Intent

packages/auth/src/index.ts exports only URL helpers, but those helpers encode a real product contract:

  • Marketing derives STERLING_LOGIN_HREF from the platform API in apps/www/src/lib/marketing.ts, so calls to action leave the public marketing site and land on the hosted sign-in flow.
  • Docs uses the same buildDashboardLoginHref helper in apps/docs/src/lib/layout-options.tsx, so the top-nav button and sidebar CTA point to the same dashboard sign-in handoff contract.
  • Admin intentionally does not use this shared WorkOS/dashboard handoff; it uses a local username/password gate backed by /v1/admin/* control-plane routes.
  • The package also exposes buildPlatformLoginHref and buildPlatformLogoutHref, which match the platform API auth routes under /v1/auth/*.

This package exists so login intent stays consistent even though the caller can be a Next.js marketing page, a Next.js docs surface, a Vite admin surface, or a browser redirect into the FastAPI product API.

The deployment layer now assumes those public-host values are supplied from Infisical-backed platform syncs:

  • NEXT_PUBLIC_DASHBOARD_URL for apps/www and apps/docs
  • backend canonical origins such as APP_PUBLIC_DASHBOARD_URL for the platform API

@sterling/contracts: Shared Shapes, Not Shared Validation

packages/contracts/src/index.ts is the canonical TypeScript description of the product-facing payloads used across apps:

  • SessionResponse and SessionUser define authenticated state, provider, redirect URLs, and entitlements.
  • DashboardBootstrapResponse pulls together attorneys, firms, cities, newsroom items, default saved lists, and analytics series for the dashboard shell.
  • AttorneySearchResponse, FirmSearchResponse, SavedList, and AssistantConversation cover the remaining product workflows exposed through shared clients.

The important boundary detail is what this package does not do: the backend currently does not import @sterling/contracts. The platform API returns plain dictionaries from services/platform-api/src/rosterscraper/api/product.py, and frontend code trusts that those shapes still match the interfaces. That makes @sterling/contracts a compile-time contract package rather than a generated schema or runtime validation layer.

@sterling/data-client: Dashboard Transport Adapter

packages/data-client/src/index.ts is the only shared package that both knows the product API route structure and imports the shared contracts:

  • requestJson standardizes credentialed JSON requests and error extraction.
  • buildPlatformUrl normalizes relative /v1/* paths against VITE_PLATFORM_API_URL.
  • getSession, getDashboardBootstrap, getAttorneys, getFirms, getNewsroom, createList, addListItems, and removeListItem wrap the product API routes implemented in services/platform-api/src/rosterscraper/api/product.py.
  • streamAssistantResponse is the dashboard's SSE client for /v1/assistant/stream.

Current usage stays intentionally narrow:

  • apps/dashboard/src/context/SessionContext.tsx uses getSession.
  • apps/dashboard/src/context/SterlingDataContext.tsx uses getDashboardBootstrap.
  • apps/dashboard/src/context/ListsContext.tsx uses the saved-list mutation helpers.
  • apps/dashboard/src/pages/LoginPage.tsx uses loginWithDevSession.
  • apps/dashboard/src/pages/AiAssistantPage.tsx uses streamAssistantResponse.

The admin app does not currently use @sterling/data-client; it talks to its control-plane API directly through local request helpers. That is a useful architectural boundary: @sterling/data-client is a product-dashboard client, not a generic HTTP SDK for every frontend.

@sterling/admin-runtime: Local Operator Runtime Adapter

packages/admin-runtime is the shared Node runtime package behind the Admin MCP server. It exists because operator adapters need the same local process, env, log, readiness, and publish-package behavior whether the outer shell is Electron or a stdio MCP server.

The package owns:

  • env bundle parsing, defaulting, and secret redaction in packages/admin-runtime/src/env.ts,
  • macOS Keychain-backed AES-256-GCM env-cache storage in packages/admin-runtime/src/secure-env-store.ts,
  • local API and scrape-local worker supervision in packages/admin-runtime/src/runtime-manager.ts,
  • control-plane HTTP wrappers in packages/admin-runtime/src/control-plane-client.ts,
  • versioned snapshot_package construction in packages/admin-runtime/src/snapshot-package.ts,
  • artifact, log, and support paths in packages/admin-runtime/src/paths.ts.

The package does not own scraping, validation, press extraction, publishing semantics, or product read models. Those still belong to services/platform-api/src/rosterscraper/*. @sterling/admin-runtime is the local adapter layer that starts the backend, checks readiness, tails logs, calls backend routes, and builds the same publish-intent payload shape that the desktop lane uses.

apps/admin-mcp is the first consumer. It exposes the runtime package through MCP tools and resources such as sterling_runtime_status, sterling_runtime_start, sterling_roster_chat, sterling_publish_snapshot_to_vps, and sterling://runtime/status.

This package should stay conservative: when a capability needs new domain behavior, add or fix the backend route first, then call it from control-plane-client.ts.

Contract Flows Across Apps

Marketing and Docs -> Dashboard

The marketing and docs apps are the public entrypoints, but they do not implement auth. Instead they import @sterling/auth and link users toward the dashboard's login flow.

  • apps/www/tests/auth-intent-links.test.mjs verifies the approved marketing CTA surfaces.
  • apps/docs/src/lib/layout-options.tsx is the docs-side shell integration point for the same login contract.

The rest of the www observability stack is intentionally app-local:

  • apps/www/src/lib/observability-config.ts owns anonymous release/environment/attribution properties
  • apps/www/src/components/analytics/marketing-instrumentation.tsx bridges DOM analytics attributes into PostHog, window.dataLayer, and the marketing:interaction custom event
  • Sentry bootstrap files live at the app root because Next.js expects browser/server/edge entrypoints there

Dashboard -> Platform API

The dashboard owns the richest shared-package integration:

  1. apps/dashboard/src/main.tsx initializes app-local observability, then preloads /v1/session and /v1/bootstrap/dashboard.
  2. apps/dashboard/src/lib/observability.tsx handles route pageviews, user identification/grouping, and shared event helpers, but it does not replace the transport layer.
  3. React context providers use @sterling/data-client helpers to fetch and mutate product data.
  4. The frontend typechecks those responses against @sterling/contracts.
  5. services/platform-api/src/rosterscraper/api/product.py serves the actual /v1/* routes and now enriches API-side observability scope with authenticated user and organization context.

That flow means a product API shape change usually requires edits in three places: the FastAPI response payload, @sterling/contracts, and any dashboard consumers or helper methods that depend on the old shape.

Admin Desktop -> Local Login, Admin -> Control Plane Session

The active Electron admin renderer shares the session response shape, but not the product data client or WorkOS login helper:

  • It checks the control-plane session directly at ${VITE_CONTROL_PLANE_URL}/v1/admin/session; desktop development defaults that origin to http://127.0.0.1:13000.
  • It types that response as SessionResponse from @sterling/contracts.
  • If the operator is unauthenticated, it renders the local admin login form and posts credentials to /v1/admin/auth/login.
  • For orchestration actions it uses its own control-plane request types, which now include async 202 workflow responses and optional execution_target routing.
  • It also uses window.sterlingDesktop from the Electron preload bridge for env import, local API start/stop/restart, and scrape-local worker supervision.

This keeps admin authentication independent from dashboard WorkOS sessions while keeping its API surface independent from the dashboard product client.

Admin MCP -> Local Runtime, Control Plane, and VPS Sync

apps/admin-mcp is a non-visual operator surface for MCP clients. It talks over stdio to Codex/Claude-style hosts, then delegates to @sterling/admin-runtime.

Its boundary is intentionally similar to Electron's main-process bridge:

  1. The MCP connection itself is inert and does not start scraping.
  2. The operator imports a trusted env bundle into the secure local cache.
  3. sterling_runtime_start launches the local API on http://127.0.0.1:13000 and starts a scrape-local,validation-publish worker.
  4. Runtime status combines process state, /healthz, /desktop/runtime/status, worker heartbeat, logs, and VPS sync health.
  5. Workflow tools call the local control-plane API for discovery, review, press monitoring, jobs, artifacts, export, and publish paths.
  6. Snapshot publishing remains explicit through sterling_publish_snapshot_to_vps, which builds a versioned snapshot_package before calling the existing /desktop/sync/publish-intent lane.

That makes MCP a full operator adapter, but not a replacement for backend orchestration.

App-local control-plane contracts

Not every important contract in this repo is exported from packages/*.

  • apps/admin-desktop/src/renderer/lib/control-plane.ts, the reference apps/legacy-admin/src/lib/control-plane.ts, and services/platform-api/apps/web/src/lib/control-plane.ts accept execution_target?: "auto" | "cloud" | "local" on discovery, preview, approved-run, and scheduled-job requests.
  • The same client layers type /runtime/readiness with worker_nodes, which lets the UI distinguish hosted worker capacity from the optional macOS scrape node.
  • Session execution metadata now carries resolved execution-target details, so the control plane can show whether a run is pending on scrape-local, executing in cloud, or falling back from auto to cloud.
  • The active admin client also owns the runtime settings contract for internal LLM routing, Browser Use CDP diagnostics, Browser Use Agent managed execution, proxy groups, browser transport, and env import.

These app-local client files are still part of the frontend/backend contract surface. When those payloads change, update the backend response shape, the app-local types, and the consuming UI together.

Shared Config Package

packages/config/tsconfig.base.json is not a business-domain package, but it still creates a cross-app contract: it defines the TypeScript defaults that apps/admin-desktop, apps/legacy-admin, and services/platform-api/apps/web compile against. The desktop renderer and the legacy/reference web shells compile against that package even though it exports no runtime code.

Change Checklist For Shared Boundaries

When a package or product API contract changes, verify the boundary in this order:

  1. Update the source endpoint or redirect behavior in the owning app/service.
  2. Update packages/contracts or packages/auth if the shared shape or URL convention changed.
  3. Update packages/data-client when the transport path, method, or payload handling changed.
  4. Update app-local clients such as apps/admin-desktop/src/renderer/lib/control-plane.ts and packages/admin-runtime/src/control-plane-client.ts when the change affects the control plane rather than the product dashboard.
  5. Update consuming apps and tests such as apps/www/tests/auth-intent-links.test.mjs.
  6. Rebuild apps/docs so the shared architecture docs stay publishable with the code they describe.

On this page