# AGENTS.md — AI Coding Agent Instructions > **For:** Claude Code, OpenAI Codex, Cursor, GitHub Copilot, Windsurf Cascade, and any AI coding agent. > **Repo:** `learning_ai_common_plat` — Shared platform packages + microservices for the ByteLyst ecosystem. > **See also:** [`README.md`](README.md) for quick start, [`docs/ECOSYSTEM_ARCHITECTURE.md`](docs/ECOSYSTEM_ARCHITECTURE.md) for full architecture. --- ## 1. Project Identity | Key | Value | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Root package** | `@bytelyst/root` | | **Library scope** | `@bytelyst/*` (packages/) | | **Service scope** | `@lysnrai/*` (services/) | | **Product consumers** | [LysnrAI](../learning_voice_ai_agent), [MindLyst](../learning_multimodal_memory_agents), [ChronoMind](../learning_ai_clock), [JarvisJr](../learning_ai_jarvis_jr), [NomGap](../learning_ai_fastgap), [PeakPulse](../learning_ai_peakpulse), [FlowMonk](../learning_ai_flowmonk), [NoteLett](../learning_ai_notes), [ActionTrail](../learning_ai_trails), [LocalMemGPT](../learning_ai_local_memory_gpt), [EffoRise](../learning_ai_efforise) | | **Product-agnostic** | Yes — every Cosmos doc includes `productId` | | **Runtime** | Node.js (ESM), TypeScript 5.7+ | | **Package manager** | pnpm (workspace) | | **Test runner** | Vitest | | **Prototype stack** | Docker Compose with Cosmos emulator, Azurite, Mailpit, Traefik, Loki, and Grafana | ## 2. Monorepo Layout ``` learning_ai_common_plat/ ├── packages/ # @bytelyst/* shared libraries │ ├── errors/ # Typed HTTP service errors (400–429) │ ├── cosmos/ # Azure Cosmos DB client singleton + container registry │ ├── config/ # Zod-based env loader + product identity + AKV resolver │ ├── auth/ # JWT utilities, auth middleware, password hashing │ ├── api-client/ # Configurable fetch wrapper with auth token injection │ ├── fastify-core/ # createServiceApp() factory + startService() helper │ ├── react-auth/ # React auth context factory (typed provider + hook) │ ├── logger/ # Structured logging wrapper (pino-based) │ ├── testing/ # Shared test mocks, fixtures, Fastify inject helpers │ ├── blob/ # Azure Blob Storage client + SAS token helpers │ ├── extraction/ # createExtractionClient(), shared types for extraction consumers │ ├── monitoring/ # Health-check utilities, Loki/Grafana helpers │ ├── llm-router/ # Deterministic LLM router: provider/model selection, fallback, health │ └── design-tokens/ # Cross-platform tokens (JSON → CSS/TS/Kotlin/Swift) │ ├── tokens/bytelyst.tokens.json # ← CANONICAL SOURCE │ ├── scripts/generate.ts # Token generator │ └── generated/ # Output: tokens.css, tokens.ts, MindLystTokens.kt, MindLystTheme.swift ├── dashboards/ # Product-agnostic web dashboards (Next.js) │ ├── admin-web/ # Platform admin console (port 3001) │ └── tracker-web/ # Issue tracker + public roadmap (port 3003) ├── services/ # @lysnrai/* product-agnostic microservices │ ├── platform-service/ # Product-agnostic platform: auth, audit, flags, notifications, blob, │ │ # invitations, referrals, promos, subscriptions, usage, plans, │ │ # licenses, stripe, items, comments, votes, public (port 4003) │ │ # NOTE: Product-specific modules migrated to product repos' backend/ │ ├── extraction-service/ # LangExtract text extraction + Python sidecar (port 4005) │ └── monitoring/ # Loki + Grafana config, health-check script ├── scripts/ # DevOps scripts (pnpm workspace member) │ ├── encrypt-migrate.ts # Batch-encrypt plaintext Cosmos docs (10 products, 40+ fields) │ └── package.json # @bytelyst/scripts — deps: @azure/cosmos, @bytelyst/field-encrypt ├── docs/ # Architecture docs, roadmap, analysis ├── package.json # Root scripts: build, test, typecheck, clean, prototype:self-test ├── pnpm-workspace.yaml # Workspace: packages/* + services/* + dashboards/* + scripts ├── tsconfig.base.json # Shared TS config (ES2022, NodeNext, strict) ├── vitest.config.ts # Root vitest config (passWithNoTests) ├── docker-compose.yml # Prototype stack: services + Cosmos emulator + Azurite + Mailpit + monitoring ├── .env.example # Required env vars template └── .editorconfig # Editor settings ``` ## 2A. Prototype Runtime Conventions - The current single-host prototype is defined by [`docker-compose.yml`](docker-compose.yml). - Prototype state currently lives in: - Cosmos DB Emulator - Azurite blob storage - Mailpit SMTP sandbox - Reuse the existing prototype diagnostics instead of adding parallel health endpoints: - `GET /health` - `GET /api/health/dependencies` - `GET /api/self-test` - `GET /api/self-test.json` - The canonical host-side smoke test command is `pnpm prototype:self-test`. - The underlying implementation is [`scripts/prototype-self-test.sh`](scripts/prototype-self-test.sh). Extend it instead of creating duplicate one-off prototype scripts. - If you change prototype infra, also update: - [`README.md`](README.md) - [`docs/PROTOTYPE_DEPLOYMENT.md`](docs/PROTOTYPE_DEPLOYMENT.md) - [`docker-compose.yml`](docker-compose.yml) - [`.env.example`](.env.example) when tracked defaults change ### Current local prototype endpoints - `platform-service`: `http://localhost:4003` - `extraction-service`: `http://localhost:4005` - `mcp-server`: `http://localhost:4007` - Cosmos Data Explorer: `http://localhost:1234` - Azurite blob endpoint: `http://localhost:10000` - Mailpit SMTP: `localhost:1025` - Mailpit inbox UI: `http://localhost:8025` ## 3. Tech Stack Rules ### TypeScript (all packages + services) - **Module system:** ESM (`"type": "module"` everywhere) - **TS target:** ES2022, `moduleResolution: NodeNext` - **Base config:** All packages/services extend `../../tsconfig.base.json` - **Builds:** `tsc` — outputs to `dist/` - **Tests:** Vitest with `passWithNoTests: true` at root ### Service framework (Fastify) - **Framework:** Fastify 5 with Zod validation - **Module pattern:** `types.ts` → `repository.ts` → `routes.ts` per module - **Auth:** JWT via `jose` — platform-service issues, all others validate - **Database:** Azure Cosmos DB via `@azure/cosmos` - **Logging:** Fastify built-in `req.log` / `app.log` (never `console.log`) - **Health:** Every service exposes `GET /health` → `{ status: "ok", service, requestId }` - **Request tracing:** `x-request-id` header propagated across all services - **Dev mode:** `tsx watch src/server.ts` ### Package conventions - All packages export from `src/index.ts` → `dist/index.js` - Use `exports` field in `package.json` (not just `main`) - Peer dependencies for heavy/shared deps (`@azure/cosmos`, `jose`, `bcryptjs`, `react`, `zod`) - Workspace deps: `"@bytelyst/errors": "workspace:*"` - If a dashboard or app consumes a local package outside the pnpm workspace, build the package first and import from `dist/`, not raw `src/` ## 4. Coding Conventions ### MUST follow - Every Cosmos document MUST include a `productId` field - Every REST endpoint MUST validate input with Zod schemas - Every service MUST propagate `x-request-id` headers - Prototype infra changes MUST preserve `pnpm prototype:self-test` - Prototype dependency checks belong in the shared status/self-test surfaces, not ad hoc endpoints - Use `PRODUCT_ID` from `@bytelyst/config` (`loadProductIdentity()`) — never hardcode - Services use self-contained Zod config schemas in `src/lib/config.ts` (avoids zod version mismatch with shared packages) - Services re-export from `@bytelyst/*` in their `src/lib/` files (`errors.ts`, `cosmos.ts`, `product-config.ts`) - For LLM routing, prefer `@bytelyst/llm-router` as the source of truth; do not introduce parallel routing logic unless explicitly required - Commit messages: `type(scope): description` — types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore` ### MUST NOT do - Never use `console.log` in production code — use `req.log` or `app.log` in Fastify - Never use `any` type — use Zod inference or explicit types - Never hardcode secrets or API keys - Secret guardrails: Husky runs `scripts/secret-scan-staged.sh` (pre-commit) and `scripts/secret-scan-repo.sh` (pre-push). See `docs/WINDSURF/CODEX_SESSION_SUMMARY_AND_PLAYBOOK.md`. - Never commit real emulator keys or blob account keys in tracked files; keep placeholders in `.env.example` - Never modify tests to make them pass — fix the actual code - Never delete existing comments or documentation unless explicitly asked - Never add emojis to code unless explicitly asked ## 5. Design System (Critical) ### NEVER hardcode colors **All colors MUST come from `@bytelyst/design-tokens`.** Hardcoded hex values create inconsistency and maintenance debt. | Platform | ❌ DON'T | ✅ DO | | ------------------ | ---------------------------- | ------------------------------------------- | | **Web** | `color: '#5A8CFF'` | `color: var(--ml-accent-primary)` | | **Web (Tailwind)** | `bg-[#5A8CFF]` | `bg-[var(--ml-accent-primary)]` | | **iOS** | `Color(hex: 0x5A8CFF)` | `MindLystColors.darkAccentPrimary` | | **Android/KMP** | `Color(0xFF5A8CFF)` | `Color(MindLystTokens.Dark.ACCENT_PRIMARY)` | | **React Native** | `backgroundColor: '#5A8CFF'` | `tokens.colors.accentPrimary` | ### Token file locations ``` packages/design-tokens/ ├── tokens/bytelyst.tokens.json # ← CANONICAL SOURCE (edit this) ├── generated/ │ ├── tokens.css # Web: CSS custom properties │ ├── tokens.ts # TypeScript constants │ ├── MindLystTokens.kt # Kotlin/KMP/Android │ ├── MindLystTheme.swift # Swift/iOS │ └── react-native/tokens.ts # React Native └── scripts/ ├── generate.ts # Main generator ├── generate-react-native.ts # RN generator ├── validate-tokens.cjs # Validation script └── token-coverage.cjs # Coverage report ``` ### How to update tokens 1. **Edit** `packages/design-tokens/tokens/bytelyst.tokens.json` 2. **Run** `pnpm --filter @bytelyst/design-tokens generate` 3. **Copy** generated files to consumer repos (see per-repo AGENTS.md) 4. **Commit** both the JSON source AND generated files ### Product-specific token sections Each product has a dedicated section in `bytelyst.tokens.json`: | Product | Token Section | Example | | ---------- | ------------------ | ------------------------------------ | | MindLyst | `color.brain` | `BRAIN_WORK`, `BRAIN_HOME` | | JarvisJr | `color.jarvisjr` | `AGENT_COACH`, `AGENT_LINGUA` | | PeakPulse | `color.peakpulse` | `ACTIVITY_HIKE`, `SPEED_ZONE_FAST` | | ChronoMind | `color.chronomind` | `URGENCY_CRITICAL`, `FOCUS_MODE` | | NomGap | `color.nomgap` | `STAGE_KETOSIS`, `AUTOPHAGY_METER` | | LysnrAI | `color.lysnrai` | `RECORDING_ACTIVE`, `DICTATION_MODE` | ### Validation Check for hardcoded colors before committing: ```bash # In any product repo node ../learning_ai_common_plat/packages/design-tokens/scripts/validate-tokens.cjs src/ # Get coverage report node ../learning_ai_common_plat/packages/design-tokens/scripts/token-coverage.cjs src/ ``` **CI Integration:** All PRs should run the validation script and fail if new hardcoded colors are introduced. ### Current adoption status (2026-03-03) | Product | Token Adoption | Status | | ---------------- | -------------- | --------------------------- | | MindLyst iOS | 100% | ✅ Good | | MindLyst Android | 100% | ✅ Good | | ChronoMind Web | 0% | ❌ Critical | | ChronoMind iOS | 0% | ❌ Critical | | PeakPulse iOS | 0% | ❌ Needs tokens | | NomGap | 0% | ❌ Critical (466 hardcoded) | | LysnrAI iOS | 0% | ❌ Critical | | JarvisJr iOS | 0% | ❌ Critical | See full audit: [`docs/design-system/DESIGN_SYSTEM_AUDIT_2026-03-03.md`](docs/design-system/DESIGN_SYSTEM_AUDIT_2026-03-03.md) ## 6. File Ownership Map | Domain | Location | Key Files | | ----------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | **Errors** | `packages/errors/` | `src/index.ts` — `BadRequestError`, `UnauthorizedError`, `ForbiddenError`, `NotFoundError`, `ConflictError`, `RateLimitError` | | **Cosmos client** | `packages/cosmos/` | `src/index.ts` — `getCosmosClient()`, `getContainer()`, container registry | | **Config / Product ID** | `packages/config/` | `src/index.ts` — `loadEnvConfig()`, `loadProductIdentity()`, `getProductId()` | | **JWT / Auth** | `packages/auth/` | `src/index.ts` — `signJwt()`, `verifyJwt()`, `hashPassword()`, `verifyPassword()`, auth middleware | | **API client** | `packages/api-client/` | `src/index.ts` — `createApiClient()` with token injection | | **React auth** | `packages/react-auth/` | `src/index.ts` — `createAuthContext()` factory (provider + hook) | | **LLM router** | `packages/llm-router/` | `src/router.ts` — route/plan/fallback, `src/registry.ts` — providers incl. local Ollama | | **Design tokens** | `packages/design-tokens/` | `tokens/bytelyst.tokens.json` (source), `scripts/generate.ts` (generator), `generated/` (output) | | **Auth / JWT issue** | `services/platform-service/` | `src/modules/auth/` | | **Feature flags** | `services/platform-service/` | `src/modules/flags/` — FNV-1a hash for deterministic rollout | | **Blob storage** | `services/platform-service/` | `src/modules/blob/`, `src/lib/blob.ts` — SAS tokens, CRUD | | **Prototype status** | `services/platform-service/` | `src/modules/status/` — dependency health JSON, self-test JSON, self-test HTML | | **Delivery / SMTP** | `services/platform-service/` | `src/modules/delivery/` — SMTP delivery, Mailpit-backed prototype email flows | | **Audit log** | `services/platform-service/` | `src/modules/audit/` | | **Notifications** | `services/platform-service/` | `src/modules/notifications/` | | **Rate limiting** | `services/platform-service/` | `src/modules/rate-limit/` | | **Subscriptions** | `services/platform-service/` | `src/modules/subscriptions/` | | **Stripe webhooks** | `services/platform-service/` | `src/modules/stripe/` | | **Usage tracking** | `services/platform-service/` | `src/modules/usage/` | | **Plans** | `services/platform-service/` | `src/modules/plans/` | | **Licenses** | `services/platform-service/` | `src/modules/licenses/` | | **Invitations** | `services/platform-service/` | `src/modules/invitations/` | | **Referrals** | `services/platform-service/` | `src/modules/referrals/` | | **Promos** | `services/platform-service/` | `src/modules/promos/` | | **Tracker items** | `services/platform-service/` | `src/modules/items/` | | **Public roadmap** | `services/platform-service/` | `src/modules/public/` | | **Tracker comments** | `services/platform-service/` | `src/modules/comments/` | | **Tracker votes** | `services/platform-service/` | `src/modules/votes/` | | **Extraction routes** | `services/extraction-service/` | `src/modules/extract/` — POST /extract, /extract/batch, /extract/jobs, /extract/models | | **Extraction tasks** | `services/extraction-service/` | `src/modules/tasks/` — predefined task library (triage, transcript, memory-insight, etc.) | | **Extraction Python** | `services/extraction-service/` | `python/src/` — LangExtract sidecar (FastAPI :4006), extractor, task registry, language detection | | **Extraction package** | `packages/extraction/` | `src/index.ts` — `createExtractionClient()`, shared types for consumers | | **Monitoring** | `services/monitoring/` | `health-check.ts`, `loki/`, `grafana/` | ### Dashboard Consumers (via `file:` refs) The following dashboards consume `@bytelyst/*` packages: | Dashboard | Location | Packages Used | | -------------------- | ------------------------------------- | ------------------------------------------------------------ | | `admin-web` | `dashboards/admin-web/` (this repo) | api-client, auth, config, cosmos, errors, logger, react-auth | | `user-dashboard-web` | `../learning_voice_ai_agent/` | api-client, auth, config, cosmos, errors, logger, react-auth | | `tracker-web` | `dashboards/tracker-web/` (this repo) | api-client, config, cosmos, errors | **Prerequisite:** Run `pnpm build` in this repo before running `npm install` in any dashboard. ### Local Mission Control Dashboard (Extracted) The local LLM dashboard has been extracted to its own repo: `../learning_ai_local_llms/dashboard/`. It consumes `@bytelyst/llm-router` from the Gitea npm registry. ## 6. How to Run Things ```bash # ── Install ──────────────────────────────────────── pnpm install # ── Build all packages + services ────────────────── pnpm build # ── Run all tests ──────────────────────────────── pnpm test # ── Type-check everything ────────────────────────── pnpm typecheck # ── Clean dist/ in all packages ──────────────────── pnpm clean # ── Run a specific service in dev mode ───────────── pnpm --filter @lysnrai/platform-service dev # port 4003 pnpm --filter @lysnrai/extraction-service dev # port 4005 # ── Run tests for one workspace ──────────────────── pnpm --filter @lysnrai/platform-service test pnpm --filter @bytelyst/errors test pnpm --filter @bytelyst/llm-router test # ── Generate design tokens ───────────────────────── pnpm --filter @bytelyst/design-tokens generate # ── Local LLM dashboard (extracted to ../learning_ai_local_llms/) ── # cd ../learning_ai_local_llms/dashboard && npm install && npm run dev # ── Docker Compose (all services + monitoring) ───── docker compose up -d docker compose down pnpm prototype:self-test # ── Encryption migration CLI ────────────────────── npx tsx scripts/encrypt-migrate.ts --product all --dry-run # Audit all 10 backends npx tsx scripts/encrypt-migrate.ts --product lysnrai --dry-run # Single product dry-run npx tsx scripts/encrypt-migrate.ts --product chronomind # Live encrypt (requires Cosmos creds) # Requires: COSMOS_ENDPOINT, COSMOS_KEY, FIELD_ENCRYPT_KEY_PROVIDER, FIELD_ENCRYPT_KEY # ── Portable builds for consumer repos ──────────── # Pack @bytelyst/* tarballs so Docker/CI builds don't need this sibling repo ./scripts/prep-consumer.sh /path/to/consumer-dir # pack + rewrite ./scripts/prep-consumer.sh /path/to/consumer-dir --restore # undo # ── Infrastructure lint (Dockerfiles + Helm charts) ─ ./scripts/lint-infra.sh # Lint all 25 Dockerfiles + any Helm charts ./scripts/lint-infra.sh --docker # Dockerfiles only ./scripts/lint-infra.sh --helm # Helm charts only ./scripts/lint-infra.sh path/to/Dockerfile # Explicit path(s) # Requires: brew install hadolint helm # ── Cross-repo typecheck + test ────────────────────── ./scripts/typecheck-all.sh # pnpm typecheck across all 11 repos ./scripts/test-all.sh # pnpm test --run across all 11 repos # ── Health check all services ────────────────────── pnpm --filter @lysnrai/monitoring check ``` ## 7. Common Patterns ### Adding a new Fastify module 1. Create `services//src/modules//types.ts` — Zod schemas + TS interfaces 2. Create `services//src/modules//repository.ts` — Cosmos CRUD 3. Create `services//src/modules//routes.ts` — REST endpoints 4. Register in `services//src/server.ts`: `await app.register(routes, { prefix: "/api" })` 5. Add tests: `services//src/modules//.test.ts` ### Adding a new shared package 1. Create `packages//` with `package.json` (`name: "@bytelyst/"`) 2. Add `src/index.ts` with exports 3. Add `tsconfig.json` extending `../../tsconfig.base.json` 4. Heavy deps go in `peerDependencies`, not `dependencies` 5. Consumer services add `"@bytelyst/": "workspace:*"` to their `dependencies` ### Using shared packages in services Services re-export from `@bytelyst/*` in `src/lib/` for clean internal imports: ```typescript // src/lib/errors.ts export { BadRequestError, NotFoundError, ConflictError } from '@bytelyst/errors'; // src/lib/cosmos.ts export { getCosmosClient, getContainer } from '@bytelyst/cosmos'; // src/lib/product-config.ts import { loadProductIdentity } from '@bytelyst/config'; const identity = loadProductIdentity(); export const PRODUCT_ID = identity.productId; ``` ### Design token workflow 1. Edit `packages/design-tokens/tokens/bytelyst.tokens.json` 2. Run `pnpm --filter @bytelyst/design-tokens generate` 3. Copy generated files to consumer repos: - `MindLystTokens.kt` → `mindlyst-native/shared/.../theme/` - `MindLystTheme.swift` → `mindlyst-native/iosApp/` - Token CSS → `design-system/web/mindlyst.css` (token section only) ## 8. Environment Variables Required by all services (see `.env.example`): ``` COSMOS_ENDPOINT=https://.documents.azure.com:443/ COSMOS_KEY= COSMOS_DATABASE=lysnrai JWT_SECRET= ``` Prototype Docker defaults differ from production: - `COSMOS_ENDPOINT=http://cosmos-emulator:8081` - `STORAGE_PROVIDER=azure` with Azurite-backed blob config - `EMAIL_PROVIDER=smtp` with `SMTP_HOST=mailpit` - Use placeholders in tracked files; keep real local values in `.env` Additional per-service: ``` # platform-service STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= # platform-service (blob storage) AZURE_BLOB_CONNECTION_STRING= AZURE_BLOB_ACCOUNT_NAME=bytelystblobs AZURE_BLOB_ACCOUNT_KEY= # All services DEFAULT_PRODUCT_ID=lysnrai ``` ## 9. Corporate Network / Proxy Setup Development happens on a corporate network with a TLS-intercepting proxy. The `NETWORK` env var controls all proxy behavior — **no manual toggling needed**. ### Quick Reference | Tool | Corporate proxy mechanism | Config location | | -------------------------- | ------------------------------------------------------------------ | --------------------------------------------- | | **npm / pnpm** | `NPM_CONFIG_REGISTRY` → JFrog proxy, `NPM_CONFIG_STRICT_SSL=false` | `switch-network.sh` | | **Node.js** | `NODE_TLS_REJECT_UNAUTHORIZED=0` | `switch-network.sh` | | **Python (pip)** | `PIP_TRUSTED_HOST`, `http_proxy`/`https_proxy` | `switch-network.sh` | | **Gradle / Android / KMP** | Custom JVM truststore with corporate CA cert | `~/.gradle/gradle.properties` + `GRADLE_OPTS` | | **curl / general HTTP** | `http_proxy`/`https_proxy` → `cso.proxy.att.com:8080` | `switch-network.sh` | ### How it works 1. `~/.zshrc` sets `export NETWORK=corp` (or `home`) 2. `~/.zshrc` sources `scripts/switch-network.sh` from this repo 3. The script conditionally sets/unsets all proxy env vars based on `NETWORK` 4. On new shell: `🏢 NETWORK=corp — proxy active` or `🏠 NETWORK=home — direct internet` ### Key files | File | Purpose | | -------------------------------------------------------- | ---------------------------------------------------------- | | [`scripts/switch-network.sh`](scripts/switch-network.sh) | Central network switch — sets all proxy vars | | `~/.gradle/gradle.properties` | Gradle daemon JVM args (truststore) + HTTP proxy host/port | | `~/.gradle/ssl/gradle-cacerts.jks` | Java truststore = default cacerts + ATT CSO proxy CA cert | ### Gradle SSL (TLS interception) The corporate proxy (`cso.proxy.att.com`) does TLS interception — it replaces upstream TLS certificates with its own, signed by the `ATTINTERNALROOTv2` CA. Gradle's JVM doesn't trust this CA by default. **Solution:** A custom Java truststore (`~/.gradle/ssl/gradle-cacerts.jks`) that includes: - All default Java CA certificates (from `$JAVA_HOME/lib/security/cacerts`) - The AT&T CSO proxy CA certificate The truststore is passed to Gradle via: - `GRADLE_OPTS` env var (set by `switch-network.sh` when `NETWORK=corp`) — for the wrapper bootstrap JVM - `org.gradle.jvmargs` in `~/.gradle/gradle.properties` — for the daemon JVM **Recreate truststore** (needed after Java updates): ```bash mkdir -p ~/.gradle/ssl JAVA_HOME=$(/usr/libexec/java_home) cp "$JAVA_HOME/lib/security/cacerts" ~/.gradle/ssl/gradle-cacerts.jks echo | openssl s_client -connect services.gradle.org:443 \ -proxy cso.proxy.att.com:8080 -showcerts 2>/dev/null \ | awk 'BEGIN{c=0} /BEGIN CERT/{c++} c==2{print} /END CERT/&&c==2{exit}' \ > /tmp/corp-ca.pem keytool -importcert -noprompt -trustcacerts -alias att-cso-proxy \ -file /tmp/corp-ca.pem \ -keystore ~/.gradle/ssl/gradle-cacerts.jks -storepass changeit ``` ### MUST follow (network-related) - Always use `NETWORK` env var — never hardcode proxy URLs in app code - Gradle builds require `GRADLE_OPTS` with truststore when on corp network (handled automatically by `switch-network.sh`) - If a Gradle build fails with SSL errors, verify `echo $GRADLE_OPTS` shows the truststore path - If adding a new tool that fetches from the internet, add its proxy config to `switch-network.sh` - `~/.gradle/gradle.properties` is a local-only file — never commit it to any repo ### Kotlin Platform SDK (`packages/kotlin-platform-sdk/`) The shared Kotlin SDK is consumed by Android apps as a composite build via `includeBuild()` in each product's `settings.gradle.kts`. Key details: - `settings.gradle.kts` declares `pluginManagement` and `dependencyResolutionManagement` repos (required for composite builds to resolve their own deps) - `build.gradle.kts` uses the Compose compiler plugin for UI components (`SurveyUI`, `InAppMessageUI`) - Uses `kotlinOptions { jvmTarget = "17" }` (not `compilerOptions {}`) for compatibility ## 10. Dependency Graph ``` @bytelyst/errors ← no deps (foundation) @bytelyst/cosmos ← peers: @azure/cosmos @bytelyst/config ← peers: zod; includes AKV resolver (resolveKeyVaultSecrets) @bytelyst/auth ← peers: jose, bcryptjs @bytelyst/api-client ← no deps @bytelyst/react-auth ← deps: @bytelyst/api-client; peers: react @bytelyst/blob ← peers: @azure/storage-blob @bytelyst/extraction ← no deps (types + client factory) @bytelyst/monitoring ← no deps (health-check utilities) @bytelyst/llm-router ← no deps (deterministic provider/model router + local Ollama plan support) @bytelyst/fastify-core ← deps: fastify; createServiceApp() + startService() @bytelyst/logger ← deps: pino @bytelyst/testing ← deps: vitest; shared mocks + Fastify inject helpers @bytelyst/design-tokens ← no deps (standalone generator) @lysnrai/platform-service ← @bytelyst/{fastify-core, config, cosmos, errors, auth, blob} @lysnrai/extraction-service ← @bytelyst/{fastify-core, config, cosmos, errors, auth} ``` Build order: packages first (they have no inter-deps), then services. `pnpm build` handles this automatically via workspace topology. ## 11. Key Documents | When you need to... | Read this | | -------------------------------- | -------------------------------------------------------------------------------------------------- | | Understand the full architecture | [`docs/ECOSYSTEM_ARCHITECTURE.md`](docs/ECOSYSTEM_ARCHITECTURE.md) | | See the extraction roadmap | [`docs/ROADMAP.md`](docs/ROADMAP.md) | | Understand why this repo exists | [`docs/COMMON_PLATFORM_ANALYSIS.md`](docs/COMMON_PLATFORM_ANALYSIS.md) | | Quick start / consuming packages | [`README.md`](README.md) | | LysnrAI product repo conventions | [`../learning_voice_ai_agent/AGENTS.md`](../learning_voice_ai_agent/AGENTS.md) | | MindLyst native repo conventions | [`../learning_multimodal_memory_agents/AGENTS.md`](../learning_multimodal_memory_agents/AGENTS.md) | ## 12. Service Test Counts | Service / Package | Tests | Runner | | ------------------ | -------- | ------ | | platform-service | 800 | vitest | | extraction-service | 46 | vitest | | packages (various) | ~30 | vitest | | **Total** | **876+** | | > Note: billing-service, growth-service, and tracker-service were consolidated into platform-service (Feb 2026). > Product-specific modules migrated to product repo backends (see below). ## 13. Product-Specific Backends Product-specific API modules have been migrated from platform-service into each product repo's `backend/` directory: | Product | Repo | Port | Modules | Tests | | ---------- | ----------------------------------------------- | ---- | ----------------------------------------------------------------------------------------- | ----- | | PeakPulse | `../learning_ai_peakpulse/backend/` | 4010 | peak-sessions, peak-routes | 32 | | ChronoMind | `../learning_ai_clock/backend/` | 4011 | timers, routines, households, shared-timers | 130 | | JarvisJr | `../learning_ai_jarvis_jr/backend/` | 4012 | jarvis-agents, jarvis-sessions, jarvis-memory, jarvis-teams, marketplace | 198 | | NomGap | `../learning_ai_fastgap/backend/` | 4013 | fasting-sessions, fasting-protocols, body-stages, social-fasting, meal-log, push-triggers | 152 | | MindLyst | `../learning_multimodal_memory_agents/backend/` | 4014 | brains, memory, reflections, daily-briefs, streaks | 59 | Each product backend uses `@bytelyst/*` packages via `file:` refs and follows the same Fastify module pattern. ## 14. Common Pitfalls 1. **Don't import `zod` from `@bytelyst/config` in services** — services bundle their own zod version. Use self-contained Zod schemas in `src/lib/config.ts`. 2. **Don't forget `productId`** — every Cosmos document must include it. 3. **Don't use `dependencies` for heavy libs in packages** — use `peerDependencies` so consumers control the version. 4. **Don't mix up package scopes** — libraries are `@bytelyst/*`, services are `@lysnrai/*`. 5. **Don't run `npm` commands** — this is a pnpm workspace. Always use `pnpm`. 6. **Don't modify generated files directly** — edit `bytelyst.tokens.json` and re-run the generator. 7. **Build packages before testing services** — service tests may import from `@bytelyst/*` `dist/`. Run `pnpm build` first if you get import errors. 8. **Don't duplicate LLM routing logic** — update `@bytelyst/llm-router` first, then have consumers call it. --- ## Cross-Repo Automation For periodic maintenance tasks that span all ByteLyst repos (test audits, coverage gaps, dependency checks, secret scans, typecheck sweeps), see the **Coding Agent Automation Playbook**: > [`docs/devops/CODING_AGENT_AUTOMATION_PLAYBOOK.md`](docs/devops/CODING_AGENT_AUTOMATION_PLAYBOOK.md) Key tasks: workspace hygiene sweep, cross-repo test suite, backend/web coverage gap analysis, TypeScript typecheck sweep, dependency health check, secret scan, code quality audit, AGENTS.md consistency check.