{
  "enabled": {
    "max-file-lines": true,
    "max-folder-items": true,
    "import-cycles": true,
    "no-nested-imports": false,
    "vulture": true,
    "eslint": false,
    "knip": false,
    "endpoints": false,
    "classes": false,
    "no-underscore-names": true,
    "p-private": true,
    "dangling-refs": true,
    "ruff": true,
    "pyright": true
  },
  "_notes": {
    "no-nested-imports": "Off on purpose: this codebase uses function-level/lazy imports to break import cycles (400+ sites). Flagging them all is wrong for us.",
    "eslint-knip": "Node tooling deferred to a later pass.",
    "classes": "Placeholder check, not wired up. endpoints: orphaned-endpoint triage deferred.",
    "max-file-lines-exceptions": "Grandfather list of pre-existing >300-line files (existing debt, not new). Paths updated after the folder-tree restructure moved several of them. The two manager/prompt/* entries are from the agent_manager decomposition: prompt_context.py aggregates the system-prompt context builders and attachments.py is one cohesive 230-line attachment resolver; both are single-responsibility and a few lines over, not splittable without an artificial seam.",
    "max-folder-items-exceptions": "Exact-path allow for folders intentionally over the cap. The rule trips at >7 (7 items is fine, the 8th tips it), so only genuinely 8+ folders are listed. backend/ and backend/apps are FastAPI feature-package registries (each child is an app mounted in main.py); agents/ aggregates agent subsystems; agents/manager/ is the agent_manager god-object decomposition (cohesive AgentManager mixins + standalone run helpers + the streaming/permissions/prompt/session subtrees), conventionally flat like agents/ and core/ since its standalone helpers are heterogeneous and don't group cleanly; agents/manager/streaming and agents/manager/session are flat peer collections of one-module-per-concern handlers; core/, tools_lib/, tests/ are conventionally flat. Frontend: app/pages is the page registry, AgentChat/ChatInput/Settings-sections/Onboarding are organizational parents, and shared/state (Redux slices) plus hooks/steps/mcp-cards/Views are flat peer collections. scripts/, electron/, linter/checks/ are flat tool dirs. These replaced blanket .lintignore-max-folder-items sentinels (backend, frontend, scripts, electron, linter/checks) so the rule still catches NEW unplanned bloat everywhere else. Kept as whole-subtree sentinels on purpose: debugger/ (self-contained injected sub-tool with its own Vite GUI), webapp_template (Vite scaffold payload), and vendored mcp-bundles. 2026-07 desktop-shell additions: Dashboard canvas/cards/desktop + hooks/interaction + hooks/lifecycle, AgentChat bubbles/tool-ui, and shared/styles are flat peer collections (one component or hook per concern) that crossed 7 as the redesign surface grew. frontend/src/toolui carries a whole-subtree .lintignore: vendored tool-ui component library (pierre), same treatment as mcp-bundles. openswarm-edge/app is the edge's flat one-module-per-concern set (routing, bundles, inject, ratelimit, sandbox, and the vendored code_safety gate); it crossed 7 when the sandbox's static gate was split out to mirror the desktop file byte for byte. AgentChat/parsing joined when the narration/deliverable classifier landed: it is the same flat one-module-per-parser collection as the rest of that subtree. 2026-08-03 browser merge: agents/browser is the flat one-module-per-concern browser tier (40 modules) that arrived whole from eric/browser-merged; .github/workflows crossed 7 when the packaged-smoke and intel-verify workflows landed; frontend/ is a package root, not a code folder. components/overlays is the flat one-component-per-overlay collection; it crossed 7 when the mandatory sign-in gate landed as component + pure predicate + its test.",
    "import-cycles": "Flags RUNTIME circular imports only (SCC>1). Skips type-only imports (import type / export type) and dynamic import() since neither runs at module init, which is why the idiomatic Redux store<->hooks type cycle is not flagged. Frontend alias resolution comes from import-cycle-aliases. Zero cycles today; the check keeps it that way.",
    "ruff + pyright": "Ported from Haik's linter (haik/feat/ingest). ruff is narrowed to F401/F811/F841 (unused imports/redefs/locals) and intentionally DROPS Haik's ARG001/ARG002 (unused args): our SDK-callback signatures require unused params (can_use_tool/pre_tool_hook take a `context` they don't use) and we ban the `_unused` prefix, so ARG is noise here. pyright runs Haik's existence-only config (typeCheckingMode off) with reportAttributeAccessIssue ENABLED: the AgentManager behavior classes now inherit a typing-only AgentManagerProtocol base (manager/AgentManagerProtocol.py) that declares the composed __init__ state + cross-class methods, so the checker sees self.sessions etc. from inside a mixin. pyright caught real bugs: a dangling `_conns` ref + TWO broken lazy imports (`_load_all`/`_load` from outputs.py, renamed to load_all/load in workspace_io but the import sites weren't updated \u2014 App Builder workspace seeding/name-sync was silently failing in a try/except). The one grandfathered SURFACE file (handle_assistant_message) is the SDK-optional try/except-import boundary (TextBlock=object fallback defeats isinstance narrowing). Both grandfather pre-existing debt by file; the refactor surface is clean. Requires `ruff` + `pyright` on PATH (added to requirements-dev.txt); pyright's config expects the venv at backend/.venv.",
    "no-underscore-names + p-private": "Convention checks ported verbatim from Haik's linter (haik/feat/ingest): no-underscore-names bans leading-underscore names (a dead-code-tooling blind spot; use p_ for private), p-private enforces that p_-prefixed names are accessed only inside their owning file/class (cross-file/class use means the name should be public). Backend Python only. The exception lists grandfather pre-existing debt that landed with the workflows/analytics forward-ports (eric's 'don't mass-migrate untouched files' rule); the agent_manager refactor surface is clean. NOTE: Haik's full linter (his branch also adds pyright + ruff and runs a different enabled set) should eventually supersede this; these two were lifted to enforce the p_ conventions on eric/dev now. browser_cookies.py and its Windows round-trip test are excepted for `_fields_` only: a ctypes.Structure protocol name required by the ctypes metaclass, not our naming.",
    "dangling-refs": "Every *_id / *_ids field on a backend pydantic model must name the entity it points at, in backend/config/entity_references.py. A model's own primary key is spelled `id`, which never matches the suffix, and neither do words that merely END in id (uuid, grid, valid) since the underscore is required. 42 of the 74 existing fields are declared in the registry (sessions, dashboards, workflows, workflow runs, apps/outputs, workspaces); the 32 listed here are grandfathered debt, and the entry is keyed <path>::<Model>.<field> rather than by file ON PURPOSE, so a NEW id field added to an already-listed model is still caught (a file glob would exempt workflows/models.py forever, which is exactly where the next dangling pointer lands). The grandfathered set is what does not resolve against a store: renderer-owned live objects (browser_id, selected_browser_ids, selected_setting_ids), ids internal to a single record (active_branch_id, msg_id, parent_id, fork_point_message_id, compacted_through_msg_id), external protocol ids we do not own (sdk_session_id, client_message_id, connection_id, installation_id, user_id), telemetry echoes (analytics bridges), and the skill-registry / .swarm-bundle entities that have no backend store module yet. Move an entry out of this list and into the registry when its entity gets one. backend/tests/*::* is blanket-exempt: a test-local model is not a persisted entity. The registry is checked back both ways, so an entry for a deleted field, or a store whose lookup function was renamed, is an error too."
  },
  "rules": {
    "max-file-lines": 300,
    "max-folder-items": 7,
    "import-cycle-aliases": {
      "@/": "frontend/src/"
    },
    "vulture-min-confidence": 1,
    "vulture-error-threshold": 1,
    "no-nested-imports": true,
    "endpoint-ignore-routes": [
      "*/callback",
      "*/callback/*"
    ],
    "ruff-select": "F401,F811,F841"
  },
  "include_extensions": [
    ".py",
    ".ts",
    ".tsx",
    ".js",
    ".jsx"
  ],
  "exclude": [
    "node_modules",
    ".venv",
    "dist",
    "build",
    "__pycache__",
    ".git",
    ".cursor",
    ".vscode",
    ".claude",
    ".pytest_cache",
    ".mypy_cache",
    ".ruff_cache",
    ".account-factory",
    ".local-stash",
    ".DS_Store",
    "python-env",
    "build-staging",
    "webapp_template_cache",
    "openswarm-cloud",
    "uv-bin",
    "data",
    "public",
    "openswarm_debug.egg-info"
  ],
  "exceptions": {
    "max-file-lines": [
      "backend/apps/agents/show_ui_mcp_server.py",
      "backend/apps/agents/agents.py",
      "backend/apps/agents/proxy/anthropic_proxy.py",
      "backend/apps/agents/proxy/anthropic_to_openai.py",
      "backend/apps/agents/browser/browser_agent.py",
      "backend/apps/agents/browser_agent_mcp_server.py",
      "backend/apps/agents/browser/browser_schema.py",
      "backend/apps/agents/core/ws_manager.py",
      "backend/apps/agents/manager/prompt/prompt_context.py",
      "backend/apps/agents/manager/prompt/attachments.py",
      "backend/apps/agents/providers/pricing.py",
      "backend/apps/agents/providers/registry.py",
      "backend/apps/dashboards/dashboards.py",
      "backend/apps/discord_mcp_shim/server.py",
      "backend/apps/mcp_registry/mcp_registry.py",
      "backend/apps/nine_router/oauth.py",
      "backend/apps/nine_router/process.py",
      "backend/apps/nine_router/sync_custom.py",
      "backend/apps/outputs/outputs.py",
      "backend/apps/outputs/runtime.py",
      "backend/apps/outputs/view_builder_templates.py",
      "backend/apps/outputs/webapp_template/frontend/src/shared/styles/ThemeContext.tsx",
      "backend/apps/service/client.py",
      "backend/apps/service/service.py",
      "backend/apps/settings/settings.py",
      "backend/apps/skills/skills.py",
      "backend/apps/subscription/router.py",
      "backend/apps/tools_lib/tools_lib.py",
      "backend/apps/web/web.py",
      "backend/main.py",
      "backend/tests/test_disconnect_resilience.py",
      "backend/tests/test_outputs_runtime_cleanup.py",
      "backend/tests/test_service.py",
      "backend/tests/test_skill_registry_community.py",
      "backend/tests/test_streaming_harness.py",
      "backend/tests/test_swarm_bundle.py",
      "backend/tests/test_v2_invariants.py",
      "backend/tests/test_v2_label_logic.py",
      "electron/affiliateTracking.test.js",
      "electron/main.js",
      "frontend/src/app/Main.tsx",
      "frontend/src/app/components/editor/CommandPicker.tsx",
      "frontend/src/app/components/editor/DirectoryBrowser.tsx",
      "frontend/src/app/components/overlays/DynamicIsland.tsx",
      "frontend/src/app/components/overlays/GlobalSearchPalette.tsx",
      "frontend/src/app/components/Layout/AppShell.tsx",
      "frontend/src/app/components/Onboarding/OnboardingPanel.tsx",
      "frontend/src/app/components/Onboarding/ac/AgenticCursor.tsx",
      "frontend/src/app/components/Onboarding/ac/acRuntime.ts",
      "frontend/src/app/components/overlays/PlanPicker.tsx",
      "frontend/src/app/components/editor/RichPromptEditor.tsx",
      "frontend/src/app/components/overlays/SignInGate.tsx",
      "frontend/src/app/components/editor/useDomElementSelector.ts",
      "frontend/src/app/pages/AgentChat/AgentChat.tsx",
      "frontend/src/app/pages/AgentChat/shell/ApprovalBar.tsx",
      "frontend/src/app/pages/AgentChat/shell/BrowserAgentInlineFeed.tsx",
      "frontend/src/app/pages/AgentChat/bubbles/MessageBubble.tsx",
      "frontend/src/app/pages/AgentChat/parsing/toolLabels.ts",
      "frontend/src/app/pages/Analytics/PixelChart.tsx",
      "frontend/src/app/pages/Commands/Commands.tsx",
      "frontend/src/app/pages/Dashboard/cards/AgentCard.tsx",
      "frontend/src/app/pages/Dashboard/cards/BrowserAgentOverlay.tsx",
      "frontend/src/app/pages/Dashboard/cards/BrowserCard.tsx",
      "frontend/src/app/pages/Dashboard/canvas/DashboardHeader.tsx",
      "frontend/src/app/pages/Dashboard/DashboardToolbar.tsx",
      "frontend/src/app/pages/Dashboard/cards/DashboardViewCard.tsx",
      "frontend/src/app/pages/Dashboard/cards/NoteCard.tsx",
      "frontend/src/app/pages/Dashboard/hooks/interaction/useCanvasControls.ts",
      "frontend/src/app/pages/DashboardSelection/DashboardSelection.tsx",
      "frontend/src/app/pages/Modes/Modes.tsx",
      "frontend/src/app/pages/Skills/SkillBuilderChat.tsx",
      "frontend/src/app/pages/Skills/Skills.tsx",
      "frontend/src/app/pages/Views/ViewEditor.tsx",
      "frontend/src/app/pages/Views/ViewPreview.tsx",
      "frontend/src/app/pages/Views/useIframeElementSelector.ts",
      "frontend/src/shared/browserCommandHandler.ts",
      "frontend/src/shared/state/agentsSlice.ts",
      "frontend/src/shared/state/dashboardLayoutSlice.ts",
      "frontend/src/shared/ws/WebSocketManager.ts",
      "backend/apps/workflows/cloud/client.py",
      "backend/apps/agents/browser/browser_batch_replay.py",
      "backend/apps/agents/browser/browser_loop.py",
      "backend/apps/agents/browser/browser_prestage.py",
      "backend/apps/agents/browser/browser_send_script.py",
      "backend/apps/agents/browser/browser_skills.py",
      "backend/apps/onboarding/usage/browser_cookies.py",
      "backend/tests/test_browser_agent_loop.py",
      "backend/tests/test_browser_skills.py",
      "frontend/src/shared/state/settingsSlice.ts",
      "frontend/src/app/components/overlays/SignInDialog.tsx"
    ],
    "max-folder-items": [
      "backend",
      "backend/apps",
      "backend/apps/agents",
      "backend/apps/agents/core",
      "backend/apps/agents/manager",
      "backend/apps/agents/manager/session",
      "backend/apps/agents/manager/streaming",
      "backend/apps/outputs",
      "backend/apps/reddit_mcp_shim",
      "backend/apps/service",
      "backend/apps/tiktok_mcp_shim",
      "backend/apps/tools_lib",
      "backend/apps/x_mcp_shim",
      "backend/tests",
      "electron",
      "frontend/src/app/components/Onboarding",
      "frontend/src/app/components/Onboarding/steps",
      "frontend/src/app/pages",
      "frontend/src/app/pages/AgentChat",
      "frontend/src/app/pages/AgentChat/ChatInput",
      "frontend/src/app/pages/AgentChat/ChatInput/hooks",
      "frontend/src/app/pages/AgentChat/bubbles",
      "frontend/src/app/pages/AgentChat/mcp-cards",
      "frontend/src/app/pages/AgentChat/parsing",
      "frontend/src/app/pages/AgentChat/tool-ui",
      "frontend/src/app/pages/Dashboard/canvas",
      "frontend/src/app/pages/Dashboard/cards",
      "frontend/src/app/pages/Dashboard/desktop",
      "frontend/src/app/pages/Dashboard/hooks/interaction",
      "frontend/src/app/pages/Dashboard/hooks/lifecycle",
      "frontend/src/app/pages/Settings/sections",
      "frontend/src/app/pages/Views",
      "frontend/src/shared",
      "frontend/src/shared/hooks",
      "frontend/src/shared/state",
      "frontend/src/shared/styles",
      "linter/checks",
      "openswarm-edge/app",
      "scripts",
      "backend/apps/workflows/cloud",
      "backend/apps/agents/browser",
      ".github/workflows",
      "frontend",
      "frontend/src/app/components/overlays"
    ],
    "no-nested-imports": [],
    "import-cycles": [],
    "vulture": [
      "backend/tests/*"
    ],
    "endpoints": [],
    "classes": [],
    "no-underscore-names": [
      "backend/apps/onboarding/usage/browser_cookies.py",
      "backend/tests/test_browser_cookies_windows_live.py",
      "backend/apps/agents/schedule_mcp_server.py",
      "backend/apps/workflows/audit.py",
      "backend/apps/workflows/escalation.py",
      "backend/apps/workflows/executor.py",
      "backend/apps/workflows/models.py",
      "backend/apps/workflows/notifier.py",
      "backend/apps/workflows/scheduler.py",
      "backend/apps/workflows/storage.py",
      "backend/apps/workflows/workflows.py",
      "backend/tests/conftest.py",
      "backend/tests/test_app_edit_bind.py",
      "backend/tests/test_executor_pipeline.py",
      "backend/tests/test_free_trial.py",
      "backend/tests/test_schedule_e2e.py",
      "backend/tests/test_schedule_recovery.py",
      "backend/tests/test_schedule_recurrence.py",
      "backend/tests/test_seed_no_clobber.py",
      "backend/tests/test_workflows_api.py",
      "backend/tests/test_workflows_semantics.py",
      "backend/tests/test_workflows_storage.py"
    ],
    "p-private": [
      "backend/apps/workflows/workflows.py",
      "backend/tests/test_schedule_recurrence.py",
      "backend/tests/test_skill_registry_community.py",
      "backend/tests/test_ssrf_guard.py",
      "backend/tests/test_workflows_semantics.py",
      "backend/tests/test_workflows_storage.py"
    ],
    "dangling-refs": [
      "backend/apps/agents/core/models.py::AgentSession.active_branch_id",
      "backend/apps/agents/core/models.py::AgentSession.browser_id",
      "backend/apps/agents/core/models.py::AgentSession.compacted_through_msg_id",
      "backend/apps/agents/core/models.py::AgentSession.sdk_session_id",
      "backend/apps/agents/core/models.py::ApprovalResponse.request_id",
      "backend/apps/agents/core/models.py::Message.branch_id",
      "backend/apps/agents/core/models.py::Message.client_message_id",
      "backend/apps/agents/core/models.py::Message.parent_id",
      "backend/apps/agents/core/models.py::MessageBranch.fork_point_message_id",
      "backend/apps/agents/core/models.py::MessageBranch.parent_branch_id",
      "backend/apps/agents/manager/Messaging.py::QueuedMessage.client_message_id",
      "backend/apps/agents/manager/Messaging.py::QueuedMessage.selected_browser_ids",
      "backend/apps/agents/manager/Messaging.py::QueuedMessage.selected_setting_ids",
      "backend/apps/agents/manager/permissions/workflow_approval.py::WorkflowApprovalMemory.current_step_id",
      "backend/apps/agents/manager/streaming/PartialReply.py::PartialReply.branch_id",
      "backend/apps/agents/manager/streaming/PartialReply.py::PartialReply.msg_id",
      "backend/apps/agents/manager/streaming/state.py::ThinkingState.msg_id",
      "backend/apps/agents/manager/streaming/state.py::TurnState.stream_text_msg_id",
      "backend/apps/apps_sdk/apps_sdk.py::GrantResolveRequest.request_id",
      "backend/apps/apps_sdk/tool_grants.py::PendingGrant.request_id",
      "backend/apps/dashboards/models.py::BrowserCardPosition.browser_id",
      "backend/apps/nine_router/credential_store.py::ProviderCredential.connection_id",
      "backend/apps/outputs/models.py::OutputVersion.parent_id",
      "backend/apps/service/analytics/agent_bridge.py::BroadcastMessage.branch_id",
      "backend/apps/service/analytics/agent_bridge.py::BroadcastMessage.parent_id",
      "backend/apps/service/analytics/frontend_bridge.py::FrontendEventProps.dashboard_id",
      "backend/apps/service/analytics/frontend_bridge.py::FrontendEventProps.step_id",
      "backend/apps/settings/models.py::AppSettings.installation_id",
      "backend/apps/settings/models.py::AppSettings.user_id",
      "backend/apps/skill_registry/skill_registry.py::p_InstallRequest.skill_id",
      "backend/apps/skill_registry/skill_registry.py::p_UpdateRequest.skill_id",
      "backend/apps/swarm/models.py::EntityRef.bundle_id",
      "backend/apps/swarm/models.py::ImportCommitResponse.root_id",
      "backend/apps/swarm/models.py::Manifest.bundle_id",
      "backend/tests/*::*"
    ],
    "ruff": [
      "backend/apps/agents/agents.py",
      "backend/apps/agents/browser/browser_agent.py",
      "backend/apps/agents/providers/registry.py",
      "backend/apps/agents/proxy/anthropic_proxy.py",
      "backend/apps/agents/proxy/anthropic_to_openai.py",
      "backend/apps/agents/tools/web.py",
      "backend/apps/dashboards/dashboards.py",
      "backend/apps/health/health.py",
      "backend/apps/modes/modes.py",
      "backend/apps/nine_router/process.py",
      "backend/apps/outputs/outputs.py",
      "backend/apps/service/buffer.py",
      "backend/apps/service/service.py",
      "backend/apps/settings/settings.py",
      "backend/apps/subscription/router.py",
      "backend/apps/swarm/redact.py",
      "backend/apps/tools_lib/tools_lib.py",
      "backend/apps/web/web.py",
      "backend/apps/workflows/models.py",
      "backend/apps/workflows/workflows.py",
      "backend/auth.py",
      "backend/main.py",
      "backend/tests/conftest.py",
      "backend/tests/test_browser_agent_loop.py",
      "backend/tests/test_browser_meta_playbook.py",
      "backend/tests/test_browser_orchestrator_routing.py",
      "backend/tests/test_bundled_extracted_modules.py",
      "backend/tests/test_disconnect_resilience.py",
      "backend/tests/test_disk_caches.py",
      "backend/tests/test_effective_tools.py",
      "backend/tests/test_outputs_runtime_cleanup.py",
      "backend/tests/test_phase1_stress.py",
      "backend/tests/test_schedule_e2e.py",
      "backend/tests/test_schedule_recurrence.py",
      "backend/tests/test_service_legacy.py",
      "backend/tests/test_settings_meta_guard.py",
      "backend/tests/test_skills_folders.py",
      "backend/tests/test_swarm_bundle.py",
      "backend/tests/test_system_prompt.py",
      "backend/tests/test_v2_invariants.py",
      "backend/tests/test_v2_label_logic.py",
      "backend/tests/test_web_mcp_decision.py",
      "backend/tests/test_workflows_semantics.py",
      "backend/tests/test_ws_integration.py"
    ],
    "pyright": [
      "backend/apps/agents/agents.py",
      "backend/apps/agents/browser_agent_mcp_server.py",
      "backend/apps/agents/manager/streaming/handle_assistant_message.py",
      "backend/apps/google_workspace_mcp_shim/run.py",
      "backend/apps/health/health.py",
      "backend/apps/settings/settings.py",
      "backend/apps/subscription/free_trial.py",
      "backend/apps/swarm/closure.py",
      "backend/apps/swarm/entities/modes.py",
      "backend/apps/web/web.py",
      "backend/apps/workflows/executor.py",
      "backend/apps/workflows/workflows.py",
      "backend/auth.py",
      "backend/config/Apps.py"
    ]
  }
}