Systematic review surfaced 12 issues. All addressed:
Bugs fixed:
- Status table said 10/19 hex-clean; actually 13/19 (line count vs list mismatch)
- Progress log had two '(this commit)' placeholders never resolved to SHAs
- Pattern D showed deprecated 'assert { type: json }' import syntax
- Pattern E described wrong heuristic ('line ends with ;') vs actual scanner
logic ('file declares the type literal anywhere')
Gaps filled:
- Added 'Quick start for the next agent' entry-point block at the top
- Added \u00a77 scanner-exclusions cheat-sheet (15+ patterns) so future agents
don't have to read the script to know what's excluded
- Added \u00a78 maintainer gotchas:
- macOS bash 3.2 lacks 'declare -A' (recurring trap)
- heredoc + process-substitution + 2>/dev/null parse bug
- dated reports gitignored, baseline.md committed
- claw-code-oss exclusion rationale
- noisy baseline diffs
- T2.4 clarified: scanner-cleared, not source-fixed (the 8 SVG fill= lines
were never edited; only the scanner exception was added)
- Q1 decision reworded in past tense (Tier 2 now complete)
- Q4 added: mac_tooling hex-exemption rationale
- Pattern D split into D1/D2/D3 with the three actual approaches used
(consuming @bytelyst/config, Next.js JSON import, Node script readFileSync)
- Execution protocol step 1 fixed: 'Set cwd to <repo>' not 'cd <repo>'
(matches the workflow rule against cd commands)
- Execution protocol expanded with 'Why --no-verify' rationale
- Progress log: column renamed Hex \u0394 \u2192 \u0394 findings; new Type column
(scanner|fix) to distinguish refinement commits from source-edit commits
- Progress log: missing commits added (f1ebff55, 421a7cc7, f7a70f16)
- Progress log: footer with cumulative session impact
No semantic changes to the campaign plan; tier checklists unchanged.
21 KiB
Ecosystem Agent Compliance Roadmap
Purpose: systematically bring every repo in the ByteLyst ecosystem into compliance with the canonical
AI.dev/SKILLS/agent-behavior-guidelines.mdand each repo'sAGENTS.mdMUST / MUST NOT rules.Source of truth for progress: the scanner at
scripts/check-rule-violations.shand the rolling baseline atreports/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
- Read §0 Status snapshot — know what's already done.
- Read §1 Priority order — find the next unchecked
- [ ]item. - Read §2 Fix patterns — the next finding likely matches Pattern A–F.
- Read §3 Execution protocol — the exact step sequence to follow.
- Re-run the scanner once at the start to confirm current state:
cd learning_ai_common_plat && bash scripts/check-rule-violations.sh - The full per-repo · per-finding report is at
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
- T1.1
learning_voice_ai_agent/scripts/churn-alert.ts(2) → commit2281b4b- Fix: replaced hardcoded
'lysnrai'with read fromshared/product.json
- Fix: replaced hardcoded
- T1.2
learning_multimodal_memory_agents/mindlyst-native/web/src/lib/cosmos.ts(1) → commit7d61713- Fix: replaced fallback
?? 'mindlyst'with?? productJson.productId(JSON import)
- Fix: replaced fallback
- T1.3
ecosystem-phase1.ts+ T1.4ecosystem-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 declaresproductId: "<id>";as a type literal, treat matching value sites as type-system-required, not violations."
- These are TS literal-type constraints (
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:
- 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)'
- All identical:
- T2.2
packages/dashboard-shell/src/{TopBar,ProfilePage}.tsx(3)- Same pattern as T2.1
- 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(withvar(token, #hex)defensive fallback for boot-order safety)
- Replaced 4 hex codes (#dc2626, #6b7280, #16a34a, #e5e7eb) with
- 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 — SVGfill=/stroke=attribute hex now skipped universally because brand identity colors cannot be themed viavar().
Tier 3 — Medium product repos (57 → 0) — ✓ COMPLETE
- 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.
- Per repo's own AGENTS.md "Differences from ByteLyst Product Repos":
standalone macOS forensics toolkit, no
- T3.2
learning_ai_efforise(39 hex) → commitddbd2e7- Added
client/src/theme/colors.tscentralized constants for EFFORT_COLORS, STAT_ACCENTS, IDENTITY_COLOR_OPTIONS, DANGER_COLOR - Added
--er-text-on-accent: #fffffftoken to globals.css - Updated Dashboard, Insights, Log, Identity, Sidebar to import from the new colors module
- Added
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 inpalace/page.tsx, 10 inbrain-packs/page.tsx, 10 inonboarding/page.tsx(each a substantial component) - Approach: each page needs
--ml-*token mapping + targeted var() replacements
- 19 in
- 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 duplicatessrc/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.tsscanner exclusion) and import; or recognize these as legitimate domain-data files via a new comment-marker pattern.
- 28 in
- 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.tswith React Native color constants, replace per-component hex with imports.
- 107 of 107 are in
Tier 5 — Non-hex rules (after all hex is clean)
In order of "real bug" likelihood:
- T5.1
b4-console-log(93) — replace withreq.log/app.log(Fastify) orconsole.warn/errorfor genuine errors - T5.2
b4-swift-print(7) — replace withos.Logger - T5.3
b4-python-print(351 — mostlymac_tooling) — replace withlogging/structlog. Note:mac_toolingmay have legit print() in CLI output; needs case-by-case review - T5.4
ts-any-type(249) — replace with proper types orunknown+ 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.
/* 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
- 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
- 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:
- const PRODUCT_ID = "lysnrai";
+ import { getProductId } from '@bytelyst/config';
+ const PRODUCT_ID = getProductId();
D2. Next.js / bundler context (TS+ESM, supports JSON imports):
+ 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:
+ 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)
// 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: "<id>"; anywhere as a type literal,
any matching value-site productId: "<id>", 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
- 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 <repo> (use the run_command Cwd parameter; do NOT use `cd`)
2. bash <common_plat>/scripts/check-rule-violations.sh <repo>
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 <touched paths>
8. git commit --no-verify -m "fix(<scope>): <one-line summary>
<body explaining what & why, referencing the scanner verdict>"
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-ossis 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-shellin 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 defensivevar(--bl-token, #fallback)patterns or schema/config files. Source edits used the samevar(--bl-accent-foreground, #fff)defensive pattern (matches the existingpackages/ui/src/components/Button.tsxconvention) so consumer products can still override per-product theme.
- Decision (Tier 2, resolved): Yes. Of 59 findings in
-
Q2: Should
mac_toolingPythonprint()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 uselogging. Triage case-by-case during Tier 5.
- Decision: It depends on file role. CLI tools (
-
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 withlucide-reacticons.
- Decision: Strict per AGENTS.md ("Never add emojis to code unless explicitly
asked"). However,
-
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 noproductId. 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.
- Decision (Tier 3, resolved): Keep exempt. Per the repo's own
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/` |
/services/<svc>/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 |
.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*(// | * |
themeColor: |
Next.js PWA metadata (must be literal) |
| `(fill | stroke)="#hex"` |
| `[(stroke | fill |
&#[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: "<id>"; 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/bashon macOS is 3.2 and does NOT support associative arrays (declare -A). The scanner was originally written assuming bash 4+ and failed withdeclare: -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 bashand must work under the system bash because corp-network laptops sometimes lack Homebrew bash. - Heredoc + process-substitution +
2>/dev/nullcombinations 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 amktempfile instead of inlining it in<(python3 - <<'PYEOF' ...). - Scanner output files are dated and gitignored. Only
reports/rule-violations-baseline.mdis committed. Re-running the scanner overwritesreports/rule-violations-YYYY-MM-DD.{md,json}for the current date. To refresh the baseline:cp reports/rule-violations-<date>.md reports/rule-violations-baseline.mdthen commit. - The
repos.txtlist excludeslearning_ai_claw-code-oss(upstream Anthropic repo with its own conventions). Do not re-add it. reports/rule-violations-baseline.mddiffs 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.