# Meshroom Agent Guide You are assisting on **Meshroom**, a node-based visual programming framework. Use the relative links and directory structure below to orient yourself in the codebase. Meshroom is a general-purpose Python/QML engine for building, editing, and executing node graphs — it provides a graph editor UI, a node execution engine, and CLI tools, but is domain-agnostic on its own. Concrete functionality is delivered through **plugins** that contribute node types and pipeline templates. Its flagship plugin is **AliceVision**, whose nodes wrap the AliceVision photogrammetry binaries; those C++ computer-vision algorithms live in the separate AliceVision repository, not here. ## Documentation Index Read the relevant source-of-truth file before working in the area it covers: * **Project, Concepts & Vocabulary:** [README.md](README.md) * **Installation & System Setup:** [INSTALL.md](INSTALL.md) — read before touching build, dependency, or environment setup. * **Plugin Architecture:** [INSTALL_PLUGINS.md](INSTALL_PLUGINS.md) — read before working on plugin loading/packaging. * **Node Development:** [NODE_DEVELOPMENT.md](NODE_DEVELOPMENT.md) — read before working on node types or their descriptors (`meshroom/nodes/`, `meshroom/core/desc/`). ## Codebase Directory Map Where this map and the actual tree diverge, trust the tree — then update the map to match (see [Workflow & Delivery](#workflow--delivery)). ``` . ├── .github/ # CI/CD workflows, issue templates, and automated testing setups ├── .vscode/ # Shared VS Code debugging and workspace configurations ├── bin/ # CLI entry points, packaged as executables in setup.py (meshroom_batch, │ # meshroom_compute, meshroom_createChunks, meshroom_info, meshroom_newNodeType, │ # meshroom_plugins, meshroom_statistics, meshroom_status, meshroom_submit). │ # The GUI has NO bin/ script — launch it with ./start.sh (see "Run the app"). ├── docker/ # Dockerfiles for containerized environments (Rocky Linux, Ubuntu, etc.) ├── docs/ # Documentation resources, developer guides, and illustrations ├── localfarm/ # Standalone local render-farm daemon (backend/client/launcher); the matching │ # submitter lives in meshroom/submitters/localFarm/ (Unix-only, uses fork) ├── meshroom/ # MAIN SOURCE CODE DIRECTORY │ ├── common/ # Qt/headless backend abstraction (BaseObject, models) used across the engine │ ├── core/ # Engine logic (Graph, Node, Attribute, execution, (de)serialization) │ │ ├── desc/ # Node/attribute DESCRIPTORS: desc.Node, desc.CommandLineNode, desc.*Param │ │ │ # (imported as `from meshroom.core import desc`) │ │ └── node/ # Live node INSTANCES, re-exported by __init__.py (import from `meshroom.core.node`): │ │ # status.py (Status, ExecMode, ChunkIndex, Node/ChunkStatusData), logManager.py, │ │ # chunk.py (NodeChunk), baseNode.py (BaseNode, Position), node.py (Node), │ │ # backdropNode.py, compatibilityNode.py (CompatibilityNode, CompatibilityIssue) │ ├── nodes/ # Concrete node types, grouped by category (e.g. general/) │ ├── submitters/ # Built-in render-farm submitters (drive meshroom_submit; e.g. localFarm) │ ├── ui/ # User Interface layer (PySide6 / QML-based components) │ │ ├── qml/ # QML design layouts (GraphEditor, NodeEditor, 3D/2D Viewers, RTI Viewer) │ │ │ └── Docking/ # Dockable panels: DockManager, DockArea, DockGroup (tabs), DockPanel, DockWindow (floating) │ │ ├── components/ # Qt helper components exposed to QML (scene3D, scriptEditor, clipboard, ...) │ │ └── ... # Python backends (app.py, graph.py, commands.py, scene.py) binding core to Qt │ ├── env.py # EnvVar registry: MESHROOM_PLUGINS_PATH / NODES_PATH / PIPELINE_TEMPLATES_PATH / LOCAL_PLUGINS, etc. │ └── multiview.py # Image-extension lists & helpers for building multiview/photogrammetry pipelines ├── plugins/ # Runtime local plugins folder (git-ignored): registries + installed plugins; seeded │ # from meshroom/core/plugins/registries/ on first run. Created next to the executables in release. ├── tests/ # Comprehensive suite of unit tests and pipeline validation tests ├── CHANGES.md # Changelog tracking features, optimizations, and API breaks ├── CMakeLists.txt # Build system file for compiling external modules/packaging ├── CONTRIBUTING.md # Guidelines for developer onboarding and codebase contributions ├── INSTALL.md # Detailed steps for building from source and configuring dependencies └── INSTALL_PLUGINS.md # Framework documentation explaining how to load custom Python plugins ``` ## How It Fits Together (Mental Model) A few distinctions are easy to confuse. Keep them straight before changing engine code: * **Descriptor vs. instance.** A *node type* is a **descriptor** class in `meshroom/nodes//.py` that subclasses `desc.Node` (Python-scripted) or `desc.CommandLineNode` (wraps an external command-line program, e.g. an AliceVision tool). It can additionally mix in `desc.InputNode` for batch/drag-and-drop initialization or `desc.OutputNode` for pipeline exports. The descriptor declares static schema only: `inputs`/`outputs` (lists of `desc.*` attributes such as `desc.File`, `desc.IntParam`, `desc.ChoiceParam`), plus `category`, `documentation`, `size`, and optional `parallelization`. `OutputNode` declares the inputs that can be configured as export settings with `outputAttributes`; its exposed `File` attributes are output folders. At runtime the engine instantiates it into a live **`Node`** (`meshroom/core/node/`) whose **`Attribute`** objects (`meshroom/core/attribute.py`) hold the actual values. Rule of thumb: `core/desc/` = schema/definition; `core/node/` + `core/attribute.py` = live, valued objects. * **Graph = DAG of attributes.** A **`Graph`** (`meshroom/core/graph.py`) holds nodes connected by **`Edge`**s that link one node's *output* attribute to another node's *input* attribute. A connected input reads its value from upstream; the graph is a DAG and defines evaluation order. Each node computes a content-based **UID** (hash of its inputs) so unchanged nodes can be cached and skipped on recompute. * **Execution = chunks.** Work is split into **`NodeChunk`**s for parallelism (driven by the descriptor's `size`/`parallelization`). `desc.Node` subclasses implement **`processChunk(chunk)`** in Python; `desc.CommandLineNode` builds a command line from its `commandLine` template plus the chunk's range and runs the external binary. **`TaskManager`** (`meshroom/core/taskManager.py`) orchestrates execution — either **locally** (`compute`) or by **submitting** to a render farm (`submit`) via `meshroom/submitters/`. * **Persistence.** Graphs are saved as **`.mg`** JSON files (`meshroom/core/graphIO.py`): a versioned `header` plus a `graph` payload. On load, `nodeFactory` reconciles descriptor changes so old projects still open — a node that no longer matches its current descriptor becomes a **`CompatibilityNode`** instead of failing. Pipeline **templates** are just `.mg` files registered at startup. Output nodes are excluded from a template by default and retained only when explicitly requested, allowing `meshroom_batch -o/--output` and the UI startup `-o/--output` to configure export destinations. * **Discovery.** Node types and pipeline templates are loaded at import time (`meshroom/core/__init__.py`, `meshroom/core/plugins/`) from the built-in `meshroom/nodes/`, the local plugins folder (`plugins/` in the Meshroom installation folder: the repository root from sources, next to the executable in release; overridable with `MESHROOM_LOCAL_PLUGINS_PATH`; one installed plugin per subfolder, plus `.json` plugin registry files), and any plugin/template paths (see [INSTALL_PLUGINS.md](INSTALL_PLUGINS.md)). * **UI bridge.** The engine is Qt-agnostic: `meshroom/common/` selects either a Qt or a headless backend for `BaseObject`, so the core runs without a UI. The `meshroom/ui/*.py` layer wraps it for Qt — `app.py` (application/entry), `graph.py` (a `UIGraph` exposing the core `Graph` as Qt models + async compute), `commands.py` (undo/redo command stack), `scene.py`. QML in `meshroom/ui/qml/` binds to these. * **Dockable panels.** The main panels (Image Gallery, Image/Text/3D Viewers, Graph Editor, Task Manager, Script Editor, Node Editor, Curve Editor) are `DockPanel`s declared once in `Application.qml`/`WorkspaceView.qml` and never destroyed: the QML `DockManager` (`meshroom/ui/qml/Docking/`) reparents them into groups of tabs following a layout tree of splits and tabs. The tree lives on the Python side: `meshroom/ui/dockLayout.py` (Qt-free, unit tested: moves, open/closed panels, sizes, validation of stored layouts) exposed and persisted in the settings by `meshroom/ui/dockLayoutManager.py` (`_dockLayout` in QML), which also stores named workspaces (View > Workspaces). Panels can also float in `DockWindow`s, transient for the main window so that its shortcuts keep working. A panel must never leave its window, even transiently (the Qt3D `Scene3D` of the 3D Viewer crashes): panels are parked in the `DockArea` of their window before any rebuild, and the 3D Viewer cannot float. ## Development & Verification * **Supported Python versions:** Target 3.9–3.11. The full test suite runs on **3.11** (Linux + Windows) in CI; `meshroom_compute` (`bin/meshroom_compute`) additionally gets a `-h` smoke test on **3.9**, the minimum supported version. Avoid syntax/features newer than 3.9 in any code reachable from it (`meshroom/core/`, CLI entry points). * **Lint:** Run `flake8 . --max-line-length=127` locally. CI ([.github/workflows/run-tests.yml](.github/workflows/run-tests.yml)) runs two passes: a **hard-failing** one for real errors (`--select=E9,F63,F7,F82` — syntax/undefined names) and a **non-blocking** style pass (`--exit-zero --max-complexity=10 --max-line-length=127`). Keep both clean; the [Code Style](#code-style) section lists the specific style warnings to avoid. * **Tests:** `pytest tests/` from the repo root. Add/run targeted tests with `pytest tests/path/to/test_file.py::test_name`. * **Run the app:** There is no `bin/` script for the GUI. Launch it with `./start.sh` (or `start.bat` on Windows) (sets `MESHROOM_ROOT`/`PYTHONPATH`, then runs `python3 meshroom/ui`), or run `python3 meshroom/ui` directly. For headless pipeline runs use `bin/meshroom_batch`. Manually verify UI/pipeline changes this way before reporting them done. ## Code Style ### Python (`meshroom/core/`, `meshroom/core/desc/`, `meshroom/nodes/`, `meshroom/ui/*.py`, `bin/`) 1. **Style Uniformity (Highest Priority):** If an existing file does not perfectly follow PEP 8 or the rules below, **always prefer code uniformity** with the surrounding codebase over strict rule enforcement. 2. **Naming Conventions:** Use **camelCase** for variable names and function/method names (e.g., `myFunction`, `nodeVariable`). Match existing repository naming patterns rather than default PEP 8 snake_case. 3. **Quality Standards (Modified PEP 8):** * **Line Length:** Do not apply the PEP 8 79/100 characters-per-line limit. Long lines are acceptable. * **Linter Compliance:** Avoid causing these specific issues: `E128` (visual indent), `E222`/`E225` (operator spacing), `E251` (spaces around parameter `=`), `E261` (2 spaces before inline comments), `E275` (space after keyword), `E301`/`E302`/`E303`/`E306` (blank line constraints), `W291`/`W292`/`W293`/`W391` (whitespaces/newlines), `E711`/`E712` (`is None`/`is True`), `F401` (unused imports), `F841` (unused variables), and `F541` (empty f-strings). 4. **Documentation & Comments:** * **Functions & Methods:** Every function or method whose purpose is not self-explanatory from its name and signature must include a clear, concise docstring covering its purpose, parameters, and return value. Trivial one-liners and obvious getters/setters may be left undocumented, matching the surrounding file. * **Complex Logic:** Add inline comments to explain non-explicit or intricate blocks of code. * **Keep it Concise:** Do not over-explain or add redundant descriptions in comments. 5. **Testing:** For changes made to **Core code** (`meshroom/core/`), you must add corresponding unit tests for any new features. ### QML / UI (`meshroom/ui/qml/`) 1. **Style Uniformity:** Match the patterns, indentation, and structure already used in the surrounding `.qml` file. 2. **Naming Conventions:** Use **camelCase** for properties, signals, and functions, consistent with standard QML/JS convention and the existing codebase. 3. **Documentation & Comments:** Same principle as Python — add comments for non-obvious or intricate logic, keep them concise, skip them where the code is self-explanatory. 4. **Testing:** Changes purely to the UI/QML layer do not require unit tests. 5. **Structure:** Split overly complex components into dedicated `.qml` files. For data models, avoid complex JavaScript implementations; instead, construct models on the Python UI side and utilize them via context properties. ## Workflow & Delivery * Provide only targeted code patches instead of full files. * Propose changes structured to perform **atomic commits** (one distinct, self-contained change per commit), one feature per PR where possible, per [CONTRIBUTING.md](CONTRIBUTING.md). * Link the relevant GitHub issue in the PR description, and open it as a draft PR while work is in progress, matching the existing contributor workflow. * **Keep this file accurate:** whenever a change makes any statement in `AGENTS.md` incorrect or incomplete — a moved/renamed path in the Directory Map, a changed command or CI setting, a shift in the architecture described by the Mental Model — update `AGENTS.md` in the same change so it never drifts from the codebase.