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
| Package | Owns | Primary exports | Major consumers | Architectural boundary |
|---|---|---|---|---|
@sterling/auth | Login/logout URL construction and return-to propagation | normalizeBaseUrl, withReturnTo, buildDashboardLoginHref, buildPlatformLoginHref, buildPlatformLogoutHref | apps/www/src/lib/marketing.ts, apps/docs/src/lib/layout-options.tsx | Keeps marketing, docs, dashboard, and platform auth redirects aligned without duplicating URL logic. |
@sterling/contracts | Shared TypeScript response and domain shapes | SessionResponse, DashboardBootstrapResponse, Attorney, Firm, NewsItem, SavedList, search result types, assistant conversation types | @sterling/data-client, dashboard contexts/pages, admin auth gate | Defines the compile-time data contract that frontend code expects from the product API. |
@sterling/data-client | Browser-facing API adapter for the product surface | requestJson, buildPlatformUrl, session helpers, dashboard bootstrap/search/news/list APIs, assistant streaming helpers | apps/dashboard/src/context/*, apps/dashboard/src/pages/LoginPage.tsx, apps/dashboard/src/pages/AiAssistantPage.tsx | Gives the dashboard a stable transport layer to /v1/* endpoints on the platform API. |
@sterling/admin-runtime | Local operator runtime supervision and control-plane adapter code | env parsing/redaction, secure env cache, runtime manager, control-plane client, snapshot package builder | apps/admin-mcp now; apps/admin-desktop can adopt the shared pieces later | Keeps MCP and Electron-style operator adapters aligned without moving scraper logic out of services/platform-api. |
packages/config | Shared TypeScript compiler policy | tsconfig.base.json | apps/admin-desktop/tsconfig.renderer.json, apps/legacy-admin/tsconfig.json, services/platform-api/apps/web/tsconfig.json | Centralizes 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_HREFfrom the platform API inapps/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
buildDashboardLoginHrefhelper inapps/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
buildPlatformLoginHrefandbuildPlatformLogoutHref, 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_URLforapps/wwwandapps/docs- backend canonical origins such as
APP_PUBLIC_DASHBOARD_URLfor 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:
SessionResponseandSessionUserdefine authenticated state, provider, redirect URLs, and entitlements.DashboardBootstrapResponsepulls together attorneys, firms, cities, newsroom items, default saved lists, and analytics series for the dashboard shell.AttorneySearchResponse,FirmSearchResponse,SavedList, andAssistantConversationcover 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:
requestJsonstandardizes credentialed JSON requests and error extraction.buildPlatformUrlnormalizes relative/v1/*paths againstVITE_PLATFORM_API_URL.getSession,getDashboardBootstrap,getAttorneys,getFirms,getNewsroom,createList,addListItems, andremoveListItemwrap the product API routes implemented inservices/platform-api/src/rosterscraper/api/product.py.streamAssistantResponseis the dashboard's SSE client for/v1/assistant/stream.
Current usage stays intentionally narrow:
apps/dashboard/src/context/SessionContext.tsxusesgetSession.apps/dashboard/src/context/SterlingDataContext.tsxusesgetDashboardBootstrap.apps/dashboard/src/context/ListsContext.tsxuses the saved-list mutation helpers.apps/dashboard/src/pages/LoginPage.tsxusesloginWithDevSession.apps/dashboard/src/pages/AiAssistantPage.tsxusesstreamAssistantResponse.
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-localworker supervision inpackages/admin-runtime/src/runtime-manager.ts, - control-plane HTTP wrappers in
packages/admin-runtime/src/control-plane-client.ts, - versioned
snapshot_packageconstruction inpackages/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.mjsverifies the approved marketing CTA surfaces.apps/docs/src/lib/layout-options.tsxis 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.tsowns anonymous release/environment/attribution propertiesapps/www/src/components/analytics/marketing-instrumentation.tsxbridges DOM analytics attributes into PostHog,window.dataLayer, and themarketing:interactioncustom 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:
apps/dashboard/src/main.tsxinitializes app-local observability, then preloads/v1/sessionand/v1/bootstrap/dashboard.apps/dashboard/src/lib/observability.tsxhandles route pageviews, user identification/grouping, and shared event helpers, but it does not replace the transport layer.- React context providers use
@sterling/data-clienthelpers to fetch and mutate product data. - The frontend typechecks those responses against
@sterling/contracts. services/platform-api/src/rosterscraper/api/product.pyserves 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 tohttp://127.0.0.1:13000. - It types that response as
SessionResponsefrom@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
202workflow responses and optionalexecution_targetrouting. - It also uses
window.sterlingDesktopfrom 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:
- The MCP connection itself is inert and does not start scraping.
- The operator imports a trusted env bundle into the secure local cache.
sterling_runtime_startlaunches the local API onhttp://127.0.0.1:13000and starts ascrape-local,validation-publishworker.- Runtime status combines process state,
/healthz,/desktop/runtime/status, worker heartbeat, logs, and VPS sync health. - Workflow tools call the local control-plane API for discovery, review, press monitoring, jobs, artifacts, export, and publish paths.
- Snapshot publishing remains explicit through
sterling_publish_snapshot_to_vps, which builds a versionedsnapshot_packagebefore calling the existing/desktop/sync/publish-intentlane.
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 referenceapps/legacy-admin/src/lib/control-plane.ts, andservices/platform-api/apps/web/src/lib/control-plane.tsacceptexecution_target?: "auto" | "cloud" | "local"on discovery, preview, approved-run, and scheduled-job requests.- The same client layers type
/runtime/readinesswithworker_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 fromautotocloud. - 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:
- Update the source endpoint or redirect behavior in the owning app/service.
- Update
packages/contractsorpackages/authif the shared shape or URL convention changed. - Update
packages/data-clientwhen the transport path, method, or payload handling changed. - Update app-local clients such as
apps/admin-desktop/src/renderer/lib/control-plane.tsandpackages/admin-runtime/src/control-plane-client.tswhen the change affects the control plane rather than the product dashboard. - Update consuming apps and tests such as
apps/www/tests/auth-intent-links.test.mjs. - Rebuild
apps/docsso the shared architecture docs stay publishable with the code they describe.