9.6 KiB
Anomalous Model Browser Architecture
This is the short entry point for maintainers and AI agents. It describes the system map, ownership boundaries, and rules that apply across subsystems. Read only the linked topic document relevant to the task; do not load every document by default.
Reading map
The prompt studio reads material prompt payloads through web/modules/material_prompt_data.js;
list summaries do not contain prompt bodies. See the Material Library contract below.
| When changing... | Read... |
|---|---|
| Python routes, storage, paths, metadata, covers, or scan state | docs/architecture/backend.md |
| Browser lifecycle, UI state, localization, media, or graph edits | docs/architecture/frontend.md |
| Workflow Recipes, packages, galleries, Parameter Notebooks, or prompt roles | docs/architecture/recipes.md |
| Material Library snapshots, image parameter details, or reusable node blocks | docs/architecture/material-library.md |
| Model Doctor, provenance hashes, missing-model recovery, or deep scanning | docs/architecture/model-resolution.md |
| Why a current product boundary exists | docs/decisions/README.md |
| Recurring implementation mistakes and post-mortems | .agents/logs/ai_lessons.md |
README.md is user-facing documentation and CHANGELOG.md is user-facing
release history. Neither is the source of truth for internal architecture.
System shape
Anomalous Model Browser is a UI-only ComfyUI extension. It registers no custom
nodes (NODE_CLASS_MAPPINGS is empty). ComfyUI loads the Vanilla JavaScript/CSS
frontend from web/; the Python package registers /anomalous/ aiohttp
routes and performs local filesystem, metadata, recipe, and scan operations.
ComfyUI frontend
web/main.js
-> web/modules/* UI, graph integration, localization
-> /anomalous/* JSON and bounded media requests
ComfyUI Python server
__init__.py
-> api/__init__.py route registration
-> api/*.py storage and domain operations
-> scraper.py explicit metadata/hash enrichment
User-owned data
ComfyUI model folders models and sidecars
user/.../anomalous_recipes workflow recipes and recipe assets
user/.../anomalous_parameters immutable parameter snapshots
user/.../anomalous_materials curated image/workflow material bundles
user/.../anomalous_notebooks prompt notes, with legacy originals preserved
The frontend and backend communicate through narrow JSON contracts. The frontend must not infer filesystem authority, and the backend must not depend on DOM or live LiteGraph state.
Ownership map
Backend
api/config.pyowns configured paths and active model-folder types.api/utils.pyowns containment and filename validation helpers.api/metadata.pyowns sidecar and safetensors metadata extraction.api/models.pyowns model listing, media serving, and model-facing routes.api/scanner.pyandscraper.pyown scan orchestration and enrichment.api/recipes.pyowns recipe validation, CRUD, history, and integrity receipts.api/recipe_packages.pyowns bounded inspect-stage-commit package handling.api/parameters.pyowns Parameter Notebook persistence and lookup.api/notebooks.pyowns Prompt Note persistence and recoverable legacy copying.api/materials.pyowns curated material persistence, private image assets, summary search/pagination, editable names/tags, and node-type lookup.model_policies.pyowns shared backend rename and protected-category policy.model_identity.pyowns file SHA-256 evidence shared with the standalone scanner.
Frontend
web/main.jsregisters the extension and owns the shared browser instance.ui_sidebar.jscreates the browser shell, navigation and settings. Its largecreateDOMmethod remains a maintenance hotspot; new tool implementations should live in their own modules rather than expanding that method.ui_grid.jsand model-detail modules own model presentation;ui_gallery.jsandui_gallery_detail.jsown generated-image browsing and inspection.ui_recipes.js/ui_recipe_detail.js,ui_notebooks.js, andui_materials.jsown their respective workspace surfaces and persistence flows.ui_prompt_composer.jsowns the standalone Prompt Studio drawer. Its child views areui_prompt_source_deck.js,ui_prompt_workbench.js, andui_prompt_inspector.js; see the frontend topic for state ownership.ui_prompt_translator.jsowns the standalone translator. Both translator and studio useui_lifecycle.jsfor global listeners, request cancellation and resize cleanup. Translation requests go throughtranslation_service.js.ui_dom.jsprovides small DOM/JSON helpers;material_inspector.jsowns material-specific metadata and parameter rendering.ui_doctor.js,model_picker.js,node_material_actions.js, andgraph_splice.jsown diagnostics and explicit graph changes.locales.jsis the shared runtime string catalog. Existing inline bilingual UI strings remain migration debt; new strings belong in the catalog.styles.cssowns presentation and theme overrides. Color values, dimensions and visual design descriptions are not duplicated as architectural contracts.
Cross-system invariants
These rules are intentionally summarized here and specified in the linked topic documents.
- Identity is provenance, not naming. Model Doctor may use a cryptographic hash, exact byte size under the allowed category policy, and target category. Paths, filenames, display names, previews, and fuzzy similarity are never identity evidence.
- Filesystem input is untrusted. Backend request paths must pass the shared
containment and filename helpers. Checking only for
..is insufficient on Windows and in the presence of alternate separators, UNC paths, or symlinks. - User files are changed transactionally and conservatively. Recipe writes, imports, graph mutations, and sidecar operations validate before mutation and either complete coherently or restore the prior state.
- The event loop stays responsive. Recursive walks, hashing, metadata parsing, and other potentially large disk operations run off the aiohttp event loop. UI rendering and media loading are bounded and cancellable.
- Host state is preserved. Browser panels are mutually exclusive, Workspace/model-detail transitions are recoverable, and graph edits use ComfyUI's change/callback contracts.
- Runtime strings are localized safely. User-visible copy comes from
locales.js; dynamic values stay outside dictionaries and enter the DOM as text. Only allowlisted rich content goes throughsafe_dom.js. - Optional integrations fail locally. Missing graph APIs, metadata, network availability, or an optional resolver may disable that capability but must not make the main extension disappear.
- Presentation data is not authority. Covers, thumbnails, summaries, cached names, and workflow fingerprints never replace the authoritative serialized workflow or model provenance record.
Data and compatibility boundaries
- Runtime settings and newly saved API keys live in
api/config.json.scraper.pymay read the legacy rootconfig.jsononly as a compatibility fallback. API keys are not stored in browserlocalStorage. - Recipes, Parameter Notebooks, and Material Library records/assets are user data outside the extension directory. They are never bundled with or silently migrated into the plugin source.
- The extension may integrate with Civitai and optional translation services only through explicit product behavior. External content and dependencies keep their own terms.
- Project code and documentation use the MIT license.
TRADEMARKS.mdseparately defines the project-name and official-branding boundary. - Internal property names and established routes may remain stable when a user-facing surface is renamed. Do not churn compatibility contracts merely to match presentation wording.
Change and snapshot protocol
Every product-code change should end as one coherent local Git snapshot:
- Run checks proportional to the changed behavior.
- Update architecture documentation only when the change modifies a module owner, data flow, public/internal interface contract, persistence format, security boundary, or critical invariant.
- When architecture changes, update the narrowest relevant topic document. Update this entry point only if the system map, cross-system invariants, or reading map changed.
- Do not add an architecture entry merely to say that existing boundaries were
unchanged. Ordinary fixes belong in code, tests, Git history, and—when useful
to users—
CHANGELOG.md. - Record a durable lesson in
.agents/logs/ai_lessons.mdonly for a recurring trap or a critical failure mode, not as a turn-by-turn work log. - Create a local commit after verification. Keep unrelated work out of the snapshot and do not push without explicit user authorization.
- Leave a clean worktree, or identify every intentional uncommitted file in the handoff.
Decision records explain enduring choices; they are not a chronological diary. Git history is the authoritative record of implementation changes. Planning-only documents must be clearly labeled as proposals and must not describe unshipped behavior as current architecture.