openclaw - 💡(How to fix) Fix Architecture: Consolidate ~15 custom boundary check scripts into unified tooling [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#59740Fetched 2026-04-08 02:41:05
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

Error Message

  1. Duplicated logic — Similar file walking, import detection, error formatting eslint --plugin openclaw --rule 'openclaw/no-extension-src-imports: error' src/

Code Example

scripts/
├── check-architecture-smells.mjs
├── check-channel-agnostic-boundaries.mjs
├── check-cli-startup-memory.mjs
├── check-extension-plugin-sdk-boundary.mjs
├── check-no-conflict-markers.mjs
├── check-no-extension-src-imports.ts
├── check-no-extension-test-core-imports.ts
├── check-no-monolithic-plugin-sdk-entry-imports.ts
├── check-no-pairing-store-group-auth.mjs
├── check-no-random-messaging-tmp.mjs
├── check-no-raw-channel-fetch.mjs
├── check-no-raw-window-open.mjs
├── check-no-register-http-handler.mjs
├── check-pairing-account-scope.mjs
├── check-plugin-extension-import-boundary.mjs
├── check-plugin-sdk-exports.mjs
├── check-plugin-sdk-subpath-exports.mjs
├── check-ts-max-loc.ts
├── check-web-search-provider-boundaries.mjs
├── check-webhook-auth-body-order.mjs
└── ... (and more)

---

- name: Run plugin extension boundary guard
  run: pnpm run lint:plugins:no-extension-imports
  
- name: Run no-random-messaging guard
  run: pnpm run lint:tmp:no-random-messaging

- name: Run channel-agnostic boundary guard
  run: pnpm run lint:tmp:channel-agnostic-boundaries

# ... 15+ more individual checks

---

// architecture-checks.config.ts
export default {
  checks: [
    {
      name: "no-extension-src-imports",
      description: "Extensions must not import from src/",
      pattern: "extensions/**/!(*.test).ts",
      forbidden: [
        { import: /^\.\.\/src\//, message: "Extensions cannot import from src/" },
      ],
    },
    {
      name: "plugin-sdk-subpaths-exported",
      description: "All plugin-sdk subpaths must be exported",
      // ... rule definition
    },
    {
      name: "no-raw-channel-fetch",
      description: "Use channel-runtime instead of raw fetch",
      // ... rule definition
    },
    // ... more checks
  ],
};

---

# Instead of 15 separate scripts:
scripts/architecture-checks/runner.ts --config architecture-checks.config.ts

# Or with filtering:
scripts/architecture-checks/runner.ts --check no-extension-src-imports

---

// eslint-plugin-openclaw
module.exports = {
  rules: {
    "no-extension-src-imports": require("./rules/no-extension-src-imports"),
    "plugin-sdk-subpaths-exported": require("./rules/plugin-sdk-subpaths-exported"),
    // ...
  },
};

---

eslint --plugin openclaw --rule 'openclaw/no-extension-src-imports: error' src/

---

// extensions/telegram/tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "openclaw/*": ["../../src/plugin-sdk/*"]
    }
  },
  "references": [{ "path": "../../src/plugin-sdk" }]
}
RAW_BUFFERClick to expand / collapse

Problem

OpenClaw maintains approximately 15 custom lint/boundary check scripts for enforcing architectural rules:

scripts/
├── check-architecture-smells.mjs
├── check-channel-agnostic-boundaries.mjs
├── check-cli-startup-memory.mjs
├── check-extension-plugin-sdk-boundary.mjs
├── check-no-conflict-markers.mjs
├── check-no-extension-src-imports.ts
├── check-no-extension-test-core-imports.ts
├── check-no-monolithic-plugin-sdk-entry-imports.ts
├── check-no-pairing-store-group-auth.mjs
├── check-no-random-messaging-tmp.mjs
├── check-no-raw-channel-fetch.mjs
├── check-no-raw-window-open.mjs
├── check-no-register-http-handler.mjs
├── check-pairing-account-scope.mjs
├── check-plugin-extension-import-boundary.mjs
├── check-plugin-sdk-exports.mjs
├── check-plugin-sdk-subpath-exports.mjs
├── check-ts-max-loc.ts
├── check-web-search-provider-boundaries.mjs
├── check-webhook-auth-body-order.mjs
└── ... (and more)

These scripts are clever but:

  1. Fragile — They grep/parse source code with regex/string matching
  2. Duplicated logic — Similar file walking, import detection, error formatting
  3. Hard to extend — Adding a new rule means writing a new script
  4. CI overhead — Each runs as a separate step in check-additional job

Current State in CI

From .github/workflows/ci.yml (lines ~400-500):

- name: Run plugin extension boundary guard
  run: pnpm run lint:plugins:no-extension-imports
  
- name: Run no-random-messaging guard
  run: pnpm run lint:tmp:no-random-messaging

- name: Run channel-agnostic boundary guard
  run: pnpm run lint:tmp:channel-agnostic-boundaries

# ... 15+ more individual checks

Proposed Solution

Option A: Unified Configuration-Driven Checker (Recommended)

Create scripts/architecture-checks/ with a config-based system:

// architecture-checks.config.ts
export default {
  checks: [
    {
      name: "no-extension-src-imports",
      description: "Extensions must not import from src/",
      pattern: "extensions/**/!(*.test).ts",
      forbidden: [
        { import: /^\.\.\/src\//, message: "Extensions cannot import from src/" },
      ],
    },
    {
      name: "plugin-sdk-subpaths-exported",
      description: "All plugin-sdk subpaths must be exported",
      // ... rule definition
    },
    {
      name: "no-raw-channel-fetch",
      description: "Use channel-runtime instead of raw fetch",
      // ... rule definition
    },
    // ... more checks
  ],
};

Single runner:

# Instead of 15 separate scripts:
scripts/architecture-checks/runner.ts --config architecture-checks.config.ts

# Or with filtering:
scripts/architecture-checks/runner.ts --check no-extension-src-imports

Option B: ESLint Plugin

Convert rules to an ESLint plugin:

// eslint-plugin-openclaw
module.exports = {
  rules: {
    "no-extension-src-imports": require("./rules/no-extension-src-imports"),
    "plugin-sdk-subpaths-exported": require("./rules/plugin-sdk-subpaths-exported"),
    // ...
  },
};

Usage:

eslint --plugin openclaw --rule 'openclaw/no-extension-src-imports: error' src/

Option C: TypeScript Project References

Use TS project references to enforce boundaries at build time:

// extensions/telegram/tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "openclaw/*": ["../../src/plugin-sdk/*"]
    }
  },
  "references": [{ "path": "../../src/plugin-sdk" }]
}

Migration Plan

Phase 1: Audit Existing Checks

Document what each check does:

CheckPurposeImplementationCan be ESLint?
check-extension-plugin-sdk-boundary.mjsEnforce plugin SDK importsAST walkYes
check-ts-max-loc.tsFile size limitsLine countNo (keep separate)
check-no-conflict-markers.mjsGit conflict markersText searchCould be git hook

Phase 2: Create Unified Runner

  1. Build config-driven checker framework
  2. Migrate 3-5 simplest checks first
  3. Run old and new in parallel during transition

Phase 3: Migrate All Checks

  • Migrate remaining checks to new system
  • Deprecate individual scripts
  • Update CI to use unified runner

Phase 4: Add IDE Integration (Optional)

  • VS Code extension for real-time feedback
  • Pre-commit hook for fast feedback

Acceptance Criteria

  • Unified checker framework created
  • At least 5 checks migrated
  • CI updated to use unified runner
  • Old scripts deprecated with migration guide
  • Documentation added for adding new checks

References

  • Current checks: scripts/check-*.mjs, scripts/check-*.ts
  • CI usage: .github/workflows/ci.yml:check-additional
  • Related: Plugin SDK at src/plugin-sdk/

Priority: Low Effort: Medium (3-5 days) Labels: architecture, refactor, tooling

extent analysis

TL;DR

Create a unified configuration-driven checker framework to replace the existing fragile and duplicated custom lint scripts.

Guidance

  • Start by auditing the existing checks to document their purpose, implementation, and potential for migration to a unified system.
  • Build a config-driven checker framework, and migrate the simplest checks first to run in parallel with the old system during the transition.
  • Update the CI to use the unified runner once a significant number of checks have been migrated.
  • Consider adding IDE integration for real-time feedback and a pre-commit hook for fast feedback as an optional step.

Example

A sample configuration for the unified checker framework could look like the provided architecture-checks.config.ts file, which defines checks with names, descriptions, patterns, and forbidden imports.

Notes

The proposed solution involves significant changes to the existing system, and careful planning and testing are necessary to ensure a smooth transition. The effort is estimated to be medium (3-5 days), and the priority is low.

Recommendation

Apply the unified configuration-driven checker framework (Option A) as the recommended solution, as it provides a flexible and scalable way to manage the custom lint scripts, reducing duplication and fragility.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Architecture: Consolidate ~15 custom boundary check scripts into unified tooling [1 participants]