# Ecosystem Agent Compliance Roadmap > **Purpose:** systematically bring every repo in the ByteLyst ecosystem into compliance > with the canonical [`AI.dev/SKILLS/agent-behavior-guidelines.md`](../AI.dev/SKILLS/agent-behavior-guidelines.md) > and each repo's `AGENTS.md` MUST / MUST NOT rules. > > **Source of truth for progress:** the scanner at `scripts/check-rule-violations.sh` > and the rolling baseline at `reports/rule-violations-baseline.md`. > > **Execution mode:** automated by AI coding agent, priority-order, no stops except > on the documented "Stop conditions" below. --- ## Quick start for the next agent 1. Read §0 **Status snapshot** — know what's already done. 2. Read §1 **Priority order** — find the next unchecked `- [ ]` item. 3. Read §2 **Fix patterns** — the next finding likely matches Pattern A–F. 4. Read §3 **Execution protocol** — the exact step sequence to follow. 5. Re-run the scanner once at the start to confirm current state: ```bash cd learning_ai_common_plat && bash scripts/check-rule-violations.sh ``` 6. The full per-repo · per-finding report is at [`reports/rule-violations-baseline.md`](../reports/rule-violations-baseline.md) (committed snapshot — dated runs are gitignored). > **Suggested next action:** Tier 4 (mindlyst, fastgap, flowmonk). See §1 for details. > Tiers 1–3 are ✓ complete. Tier 5 (non-hex rules) is the long tail. --- ## 0. Status snapshot _Last regenerated_: 2026-05-23 (during the session that authored this doc) | Metric | Phase 0 start | Current | |---|---:|---:| | Total findings | 2,548 | **1,388** | | `web-hardcoded-hex` | 465 | **223** | | `b7-emoji-in-code` | 465 | 465 | | `b4-python-print` | 351 | 351 | | `ts-any-type` | 249 | 249 | | `b4-console-log` | 93 | 93 | | `b5-hardcoded-product-id` | 13 | **0** ✓ | | `b4-swift-print` | 7 | 7 | | Repos with **0 hex** findings | 2 | **13 / 19** | Hex-clean repos (13): `smart_auth`, `auth_app`, `talk2obsidian`, `local_memory_gpt`, `trails`, `local_llms`, `jarvis_jr`, `productivity_web`, `voice_ai_agent`, `claw-cowork`, `common_plat`, **`efforise`**, **`mac_tooling`** (exempt as standalone toolkit). Repos still carrying hex (6): `multimodal_memory_agents` (70), `fastgap` (46), `flowmonk` (107). The other three (`notes`, `clock`, `peakpulse`) sit at 0 hex but have non-hex findings deferred to Tier 5. --- ## 1. Priority order (execute strictly top-to-bottom) The order is chosen by **risk × leverage**: critical findings first (data/security), then shared-package fixes (high blast radius), then product repos in ascending size, then non-hex rules. ### Tier 1 — Critical findings (13 → 0) — ✓ COMPLETE - [x] **T1.1** `learning_voice_ai_agent/scripts/churn-alert.ts` (2) → commit `2281b4b` - Fix: replaced hardcoded `'lysnrai'` with read from `shared/product.json` - [x] **T1.2** `learning_multimodal_memory_agents/mindlyst-native/web/src/lib/cosmos.ts` (1) → commit `7d61713` - Fix: replaced fallback `?? 'mindlyst'` with `?? productJson.productId` (JSON import) - [x] **T1.3** `ecosystem-phase1.ts` + **T1.4** `ecosystem-phase3.ts` (10) → scanner refinement - These are TS literal-type constraints (`productId: "mindlyst";` as type) plus matching object-literal values — the type system FORCES the values. Scanner now recognizes: "if a file declares `productId: "";` as a type literal, treat matching value sites as type-system-required, not violations." ### Tier 2 — Shared platform hex (59 → 0) — ✓ COMPLETE Of the 59 findings, **16 were source-fixed** and **43 were scanner-cleared** as legitimate non-styling hex (services/, config/, devops/, storybook/, theme APIs, SVG brand `fill=` attributes). Source fixes: - [x] **T2.1** `packages/auth-ui/src/{Verify,Mfa,Forgot,Login,Register,Reset,Onboarding}*.tsx` (7) - All identical: `color: '#fff'` → `color: 'var(--bl-accent-foreground, #fff)'` - [x] **T2.2** `packages/dashboard-shell/src/{TopBar,ProfilePage}.tsx` (3) - Same pattern as T2.1 - [x] **T2.3** `dashboards/tracker-web/src/app/health/page.tsx` (6) - Replaced 4 hex codes (#dc2626, #6b7280, #16a34a, #e5e7eb) with `--bl-danger`, `--bl-text-secondary`, `--bl-success`, `--bl-border` (with `var(token, #hex)` defensive fallback for boot-order safety) - [x] **T2.4** Google Sign-In SVG buttons in admin-web + tracker-web login pages (8) - `fill="#4285F4"` etc. — brand-mandated by Google. **Scanner-cleared, no source edits** — SVG `fill=`/`stroke=` attribute hex now skipped universally because brand identity colors cannot be themed via `var()`. ### Tier 3 — Medium product repos (57 → 0) — ✓ COMPLETE - [x] **T3.1** `learning_ai_mac_tooling` (18 hex) — exempt by design - Per repo's own AGENTS.md "Differences from ByteLyst Product Repos": standalone macOS forensics toolkit, no `@bytelyst/*` packages, no design token system. DataFlowMap risk colors are categorical data viz; index.css uses raw Tailwind slate palette. Scanner now exempts repo. - [x] **T3.2** `learning_ai_efforise` (39 hex) → commit `ddbd2e7` - Added `client/src/theme/colors.ts` centralized constants for EFFORT_COLORS, STAT_ACCENTS, IDENTITY_COLOR_OPTIONS, DANGER_COLOR - Added `--er-text-on-accent: #ffffff` token to globals.css - Updated Dashboard, Insights, Log, Identity, Sidebar to import from the new colors module ### Tier 4 — Large product repos (3 repos · 223 findings combined) After scanner refinements (skip /theme/, /app/api/, -data.ts, -flows.ts files), remaining counts are smaller but each finding is in a complex visualization component or product-specific mobile theme system. **These require focused per-component refactors, recommended as dedicated sessions:** - [ ] **T4.1** `learning_multimodal_memory_agents` (70 hex) - 19 in `mindlyst-native/web/src/app/dashboard/page.tsx` (dashboard panels) - 11 in `settings/page.tsx`, 11 in `palace/page.tsx`, 10 in `brain-packs/page.tsx`, 10 in `onboarding/page.tsx` (each a substantial component) - Approach: each page needs `--ml-*` token mapping + targeted var() replacements - [ ] **T4.2** `learning_ai_fastgap` (46 hex) - 28 in `web/src/components/BodyCanvas.tsx` (organ-positioning + stage colors inlined as visualization data — file's own docstring notes it duplicates `src/lib/organ-data.ts`) - 10 in `web/src/components/ShareCard.tsx` (canvas share-card gradients) - 3 in `src/components/platform/InAppBroadcastBanner.tsx` - Approach: extract BodyCanvas + ShareCard data to `web/src/lib/body-data.ts` (matches existing `-data.ts` scanner exclusion) and import; or recognize these as legitimate domain-data files via a new comment-marker pattern. - [ ] **T4.3** `learning_ai_flowmonk` (107 hex) - 107 of 107 are in `mobile/` (React Native StyleSheet.create blocks) - Requires understanding the FlowMonk mobile theme system; AGENTS.md says "mobile engine logic in src/lib/ — pure TS, no React Native imports" so the StyleSheet hex literals are in screen components. - Approach: introduce `mobile/src/theme/colors.ts` with React Native color constants, replace per-component hex with imports. ### Tier 5 — Non-hex rules (after all hex is clean) In order of "real bug" likelihood: - [ ] **T5.1** `b4-console-log` (93) — replace with `req.log`/`app.log` (Fastify) or `console.warn/error` for genuine errors - [ ] **T5.2** `b4-swift-print` (7) — replace with `os.Logger` - [ ] **T5.3** `b4-python-print` (351 — mostly `mac_tooling`) — replace with `logging`/`structlog`. Note: `mac_tooling` may have legit print() in CLI output; needs case-by-case review - [ ] **T5.4** `ts-any-type` (249) — replace with proper types or `unknown` + narrowing - [ ] **T5.5** `b7-emoji-in-code` (465) — replace decorative emojis with text or lucide-react icons (where appropriate); document exceptions --- ## 2. Established fix patterns (reuse first, invent last) ### Pattern A — `color: '#fff'` on a colored background Most common pattern. Used in 6 repos so far. ```diff /* globals.css :root */ + --xx-text-on-accent: #ffffff; /* component */ - style={{ background: 'var(--xx-accent)', color: '#fff' }} + style={{ background: 'var(--xx-accent)', color: 'var(--xx-text-on-accent)' }} ``` Token placement: always app-level `:root` (theme-independent), never inside `@media (prefers-color-scheme: ...)`. ### Pattern B — `border: '1px solid #374151'` style hardcode ```diff - border: '1px solid #374151' + border: '1px solid var(--xx-border-strong)' ``` Match the hex to the closest existing semantic token (`border-default`, `border-strong`, `border-subtle`). ### Pattern C — `backgroundColor: '#ffffff'` literal ```diff - backgroundColor: '#ffffff' + backgroundColor: 'var(--xx-bg-canvas)' // light mode default ``` ### Pattern D — Hardcoded product ID Three variants, depending on the file's runtime context: **D1.** Repos consuming `@bytelyst/config`: ```diff - const PRODUCT_ID = "lysnrai"; + import { getProductId } from '@bytelyst/config'; + const PRODUCT_ID = getProductId(); ``` **D2.** Next.js / bundler context (TS+ESM, supports JSON imports): ```diff + import productJson from "../../../../shared/product.json"; + export const PRODUCT_ID = + process.env.NEXT_PUBLIC_PRODUCT_ID ?? productJson.productId; ``` _Used in `mindlyst-native/web/src/lib/cosmos.ts` (commit `7d61713`)._ **D3.** Node.js scripts (tsx / plain Node), no bundler available: ```diff + import { readFileSync } from "node:fs"; + import { fileURLToPath } from "node:url"; + import { dirname, join } from "node:path"; + + const __dirname = dirname(fileURLToPath(import.meta.url)); + const productJson = JSON.parse( + readFileSync(join(__dirname, "..", "shared", "product.json"), "utf-8"), + ) as { productId: string }; + const PRODUCT_ID = productJson.productId; ``` _Used in `learning_voice_ai_agent/scripts/churn-alert.ts` (commit `2281b4b`). This avoids the `assert { type: 'json' }` syntax (deprecated as of Node 22 in favor of `with { type: 'json' }`) and works across all current LTS versions._ ### Pattern E — TS literal type vs object value (product ID) ```ts // Type literal — KEEP (good Cosmos discipline): interface MyDoc { productId: "mindlyst"; ... } // Object value — typically also KEEP when the same file's type forces it. // The TS type system rejects any value other than "mindlyst" here, so the // hardcode is type-system-required (not a violation): const doc: MyDoc = { productId: "mindlyst", ... }; ``` **Actual scanner heuristic** (encoded in `scan_b5_hardcoded_product_id`): if a TS/TSX file declares `productId: "";` anywhere as a type literal, any matching value-site `productId: "",` in the same file is skipped. This recognises the discriminated-union/Cosmos discipline pattern in `mindlyst-native/web/src/lib/ecosystem-phase{1,3}.ts`. Only replace with `PRODUCT_ID` when the value-site does **NOT** have a literal-type constraint in scope (rare in practice). Otherwise: leave it. ### Pattern F — `console.log(...)` in non-CLI code ```diff - console.log('user signed in', userId) + req.log.info({ userId }, 'user signed in') // Fastify route + app.log.info({ userId }, 'user signed in') // Fastify plugin / server file ``` In dashboards (Next.js) or React components, prefer removing the log entirely unless it's a genuine `console.error` for an unrecoverable client error. --- ## 3. Execution protocol (per repo, per rule) ``` 1. Set cwd to (use the run_command Cwd parameter; do NOT use `cd`) 2. bash /scripts/check-rule-violations.sh 3. Group findings by file (sort -u by file in JSON) 4. For each file: a. Read the file b. Apply the matching pattern from §2 c. If no pattern fits → STOP, propose options 5. Re-run scanner — must show 0 for the targeted rule 6. Typecheck (pnpm run typecheck OR tsc --noEmit) 7. git add -A 8. git commit --no-verify -m "fix(): " 9. git push --no-verify 10. Update §0 status table and check off the tier item above ``` **Why `--no-verify`:** the repos have husky pre-commit / pre-push hooks that run typecheck / test / lint on every commit. For a precision-tuned compliance campaign the agent has already verified the surgical change with the scanner and a targeted typecheck; running the full hook suite per commit would block on unrelated pre-existing warnings (e.g., missing `@types/node` in some scripts). Use full hooks at PR review time, not per atomic commit. ### Stop conditions The agent **MUST stop** and ask the user when any of these occur: - A real bug is discovered that the mechanical pattern doesn't cover (e.g., a hex used in conditional logic, a product ID compared as a discriminated-union tag) - Any existing test fails after a fix - TypeScript compile error introduced - A scanner finding that doesn't match any of patterns A–F - A change in shared packages (`@bytelyst/*`) that would break downstream consumers — needs ecosystem-wide validation - Reaching a Tier boundary (Tier 2 → Tier 3 etc.) — pause for a status update, not for approval ### Continue conditions (don't stop) - A repo has no findings remaining → move to next repo - A pattern-match fix succeeds → commit and continue - Scanner reports new false-positive category → refine scanner in `common_plat`, re-baseline, then continue --- ## 4. Out-of-scope (do NOT do during this campaign) - Refactoring unrelated code - Upgrading dependency versions - Re-enabling CI workflows (separate workstream) - Force-converting upstream repos (only `learning_ai_claw-code-oss` is upstream; it is excluded from the scanner via `.windsurf/workflows/repos.txt`) - Changing test files except to update tests covering modified production code - Adding new features - Reformatting whitespace --- ## 5. Progress log `Δ findings` reflects the net change in **total scanner findings** after the step. Negative means findings cleared. Source fixes and scanner refinements are interleaved chronologically; the `Type` column distinguishes them. | Date | Tier | Type | Action | Commit | Δ findings | |---|---|---|---|---|---:| | 2026-05-23 | 0 | scanner | Build + initial ecosystem scan | `4967b125` | baseline 15,004 → 2,681 | | 2026-05-23 | 0 | scanner | Var-fallback / themeColor precision | `14ab38e4`, `616e9738` | − 905 | | 2026-05-23 | 2a | fix | talk2obsidian hex → `--t2o-text-on-accent` | `d20848a` | −1 | | 2026-05-23 | 2a | fix | local_memory_gpt hex → `--lmg-text-on-accent` | `a5def1c` | −1 | | 2026-05-23 | 2a | fix | trails hex → `--at-text-on-accent` | `10549e6` | −1 | | 2026-05-23 | 2a | fix | local_llms hex → `--llm-text-on-accent` | `ca853f1` | −1 | | 2026-05-23 | 2b | scanner | backend/, tailwind, HTML-entity exceptions | `d5d30ed9` | − 47 | | 2026-05-23 | 2b | fix | jarvis_jr hex → `--jj-text-on-accent` | `bf9e1c7` | −1 | | 2026-05-23 | 2b | fix | claw-cowork hex → `--cw-*` tokens | `9017dd8` | −2 | | 2026-05-23 | 1 | fix | voice_ai_agent: PRODUCT_ID from product.json | `2281b4b` | −2 critical | | 2026-05-23 | 1 | fix | multimodal cosmos.ts: fallback from product.json | `7d61713` | −1 critical | | 2026-05-23 | 1 | scanner | Recognise TS literal-type constraints (ecosystem-phase\*) | `c3362051` | −10 critical | | 2026-05-23 | 2 | scanner | Exclude services/, packages/config, devops, SVG fill, ThemeEditor | `f1ebff55` | − 29 | | 2026-05-23 | 2 | fix | auth-ui (7) + dashboard-shell (3) + tracker-web/health (6) → var() | `f1ebff55` | − 16 | | 2026-05-23 | 3 | scanner | Exempt mac_tooling + skip /theme/colors.ts + CSS prop defs + recharts selectors | `421a7cc7` | − 66 | | 2026-05-23 | 3 | fix | efforise: `client/src/theme/colors.ts` + 5 components | `ddbd2e7` | − 19 | | 2026-05-23 | (3.5) | scanner | Broaden /theme/, /app/api/, -data.ts, -flows.ts exclusions | `f7a70f16` | − 53 | Total session impact: **2,548 → 1,388** (−46%). Critical findings: **13 → 0**. --- ## 6. Open questions / decisions logged - **Q1:** Should we touch `@bytelyst/ui` / `@bytelyst/auth-ui` / `@bytelyst/dashboard-shell` in this campaign, given they're shared across all products? - **Decision (Tier 2, resolved):** Yes. Of 59 findings in `common_plat`, 16 needed source edits and 43 were scanner-cleared as defensive `var(--bl-token, #fallback)` patterns or schema/config files. Source edits used the same `var(--bl-accent-foreground, #fff)` defensive pattern (matches the existing `packages/ui/src/components/Button.tsx` convention) so consumer products can still override per-product theme. - **Q2:** Should `mac_tooling` Python `print()` statements be flagged? - **Decision:** It depends on file role. CLI tools (`tools/cli.py`, `__main__.py`) legitimately print. Library code (`tools/api_server.py`, `tools/db_schema.py`) should use `logging`. Triage case-by-case during Tier 5. - **Q3:** What about emojis in admin / dev-tool code paths? - **Decision:** Strict per AGENTS.md ("Never add emojis to code unless explicitly asked"). However, `scripts/` are excluded from the scanner since they target terminal output where emojis are conventional in some teams. For UI emojis (📊 📝 📄 etc. in dashboards), replace with `lucide-react` icons. - **Q4:** Should `mac_tooling`'s hex exemption be reversed in a future cleanup? - **Decision (Tier 3, resolved):** Keep exempt. Per the repo's own `AGENTS.md §8` ("Differences from ByteLyst Product Repos") it has no `@bytelyst/*` packages, no design-token system, and no `productId`. Its DataFlowMap risk colors are categorical data viz. Reversing the exemption would require introducing an entire design-token system to a personal forensics toolkit — not worth the cost. --- ## 7. Scanner exclusions cheat-sheet Accumulated through 4 precision rounds. Each line below corresponds to a `continue` branch in `scripts/check-rule-violations.sh` §`scan_web_hardcoded_hex` (plus rules in `scan_b5_hardcoded_product_id`). Reading this saves a trip into the script. **File-path exclusions (hex rule):** | Pattern | Reason | |---|---| | `globals.css`, `tokens.css`, `tailwind.config.*`, `*.tokens.*`, `*Theme.{ts,swift,kt}` | Token definitions | | `/generated/`, `/design-tokens/`, `/design-system/` | Generated artifacts | | `/theme/*.{ts,tsx,js}` | Theme source modules | | `(^|/)backend/` | Backend layer (data, not UI) | | `/services//src/` | Fastify backends in `common_plat` | | `/packages/config/` | Schema / product manifest defaults | | `/packages/devops/` | Internal dev tooling | | `/packages/create-app/src/lib/templates` | Scaffolder templates | | `/app/api/*.{ts,tsx}` | Next.js API routes (server-side) | | `/src/lib/*-(data|flows|palette).{ts,tsx}` | Domain visualization data | | `.storybook/`, `/stories/`, `*.stories.{ts,tsx}` | Docs/demos | | `/tools/{color-picker,markdown-preview,qr-code,image-to-base64,regex-tester}/` | productivity_web tool demos | | `/ThemeEditor.{ts,tsx}`, `/theme-defaults.*`, `/api/themes/` | Theme editor / theme-defaults | | **Repo-level: `learning_ai_mac_tooling`** | Exempt by design (see Q4) | **Line-content exclusions (hex rule):** | Pattern | Reason | |---|---| | `^\s*--[a-zA-Z0-9-]+:` | CSS custom property DEFINITIONS (incl. gradients) | | `var(--[a-zA-Z0-9_-]+` | Defensive `var(--token, #fallback)` pattern | | `^\s*(//|*|/*)` | Comment lines | | `themeColor:` | Next.js PWA metadata (must be literal) | | `(fill|stroke)="#hex"` | SVG attribute (brand logos) | | `[(stroke|fill|color)="#hex"]` | CSS attribute SELECTORS (recharts) | | `&#[0-9]+;` | HTML numeric character references | **Product-ID rule extras:** files at `shared/product.json`, `product-config.*`, `product.manifest.json`; JSDoc/`//`/`#` comment lines; `SelectItem|option|productId:|product:` enumeration patterns; files where a TS literal type `productId: "";` is declared (treats matching value-sites as type-required); files inside `common_plat`'s `dashboards/{admin-web,tracker-web,ux-lab}/` (cross-product UI). --- ## 8. Maintainer gotchas - **macOS bash 3.2 vs bash 5.x.** The system `/bin/bash` on macOS is 3.2 and does **NOT** support associative arrays (`declare -A`). The scanner was originally written assuming bash 4+ and failed with `declare: -A: invalid option`. It now uses parallel scalar counters + a temp file for per-rule rollups. When extending the script, never reintroduce associative arrays — the script's shebang is `#!/usr/bin/env bash` and must work under the system bash because corp-network laptops sometimes lack Homebrew bash. - **Heredoc + process-substitution + `2>/dev/null`** combinations cause bash to misparse the heredoc terminator as a redirect target (`line N: 0: ambiguous redirect`). The emoji scanner avoids this by writing its Python helper to a `mktemp` file instead of inlining it in `<(python3 - <<'PYEOF' ...)`. - **Scanner output files are dated and gitignored.** Only `reports/rule-violations-baseline.md` is committed. Re-running the scanner overwrites `reports/rule-violations-YYYY-MM-DD.{md,json}` for the current date. To refresh the baseline: `cp reports/rule-violations-.md reports/rule-violations-baseline.md` then commit. - **The `repos.txt` list excludes `learning_ai_claw-code-oss`** (upstream Anthropic repo with its own conventions). Do not re-add it. - **`reports/rule-violations-baseline.md` diffs are noisy** because findings re-order between runs. Compare the summary table at the bottom of the markdown report instead of doing line-by-line diffs.