# BEdit Agent Guide This file is the handoff context for coding agents working in this repository. Read it before making changes. ## Working agreement - Make only the changes the user requested. - Keep completely out of unrelated code. Do not reformat, reorder, rename, clean up, or “improve” code that is outside the task. - Preserve existing user changes and assume a dirty worktree belongs to the user. - Inspect the relevant files before deciding on an implementation. - Prefer small, modular changes over growing `MainWindow`, a controller, or another file into a monolith. - When the user asks why something happens, diagnose and explain it without editing files unless they also ask for a fix. - Do not create commits unless explicitly requested. ## Code style Follow the local style in the file being edited, with these user preferences taking priority: - Prefer compact, readable one-line imports. Do not introduce parenthesized multiline imports. - Avoid spreading short function calls, conditions, and expressions across multiple lines. - Do not run broad formatters or import sorters. - Do not use a lint autofix over the project. - Keep classes and functions focused. Extract a controller, service, command, model, or reusable widget when a feature would otherwise make an existing file large. - Generated modules contain no handwritten application behavior. The project uses Ruff, but import sorting is intentionally not enforced during scoped checks: ```sh .venv/bin/ruff check --ignore I001 path/to/changed_file.py ``` ## Project structure and dependency direction Relevant GUI structure: ```text src/bedit_gui/ ├── application.py ├── commands/ ├── controllers/ ├── documents/ ├── models.py ├── services/ ├── ui/ │ ├── forms/ │ └── generated/ ├── resources/ │ └── generated/ ├── utils/ └── views/ └── models/ ``` Responsibilities: - `application.py`: composition root. Create and connect the application, document, window, services, and controllers here. - `documents/document.py`: editable document facade. Owns the core model, path, main `QUndoStack`, modified state, and high-level operations. - `commands/`: `QUndoCommand` implementations. Persistent changes to the document model go through commands. - `controllers/`: connect actions and widgets to document/service operations. Keep workflow logic out of `MainWindow`. - `views/`: handwritten widget/window/graphics behavior. - `views/models/`: Qt item models used by views. - `services/`: non-visual functionality such as files, clipboard, logging, and settings. - `models.py`: GUI metadata persisted inside the core document, currently including icons and shapes. - `bedit_core`: domain model and serialization. It must never import from `bedit_gui`. Preferred direction: ```text views/controllers ↓ documents/services ↓ commands ↓ bedit_core ``` Avoid introducing imports from `bedit_gui` into `bedit_core` or circular dependencies between services and documents. ## Qt Designer and generated files Raw forms are in: ```text src/bedit_gui/ui/forms/ ``` Generated Python is in: ```text src/bedit_gui/ui/generated/ ``` Never add handwritten behavior to generated UI modules. Change the `.ui` form and regenerate with: ```sh .venv/bin/python scripts/generate_qt_files.py ``` The generation script also fixes the package-qualified resource import. Calling `pyside6-uic` directly without the script can produce a broken `resources_rc` import. Raw resources and the QRC file live under `src/bedit_gui/resources/`. Generated resource Python lives under `src/bedit_gui/resources/generated/`. ## Undo and document changes - The main application document owns the main undo stack. - The icon editor owns a separate local undo stack. - The `Document` facade should expose high-level methods that push commands. Controllers should normally call those methods rather than construct commands. - Commands mutate the model in `redo()`/`undo()` and emit the appropriate document signals. - Multi-object user operations should be one command or one undo macro. - Allocate stable IDs and final names before pushing a command so redo reproduces the same result. - Component names must be unique within their destination component dictionary. Conflicts use `_0`, `_1`, and so on. - Copy/paste must generate new component, port, parameter, connection, and icon-shape IDs and rewrite references. ## Document tree `DocumentTreeModel` has two columns: - Column 0: editable document/component name. - Column 1: rendered component icon. Use `selectedRows(0)` for multi-selection; `selectedIndexes()` returns both columns. Filter selected descendants when an ancestor is also selected. The tree uses extended row selection. Delete, cut, and copy may operate on multiple components. Paste targets either: - the document root, or - the component dictionary of a selected graph component. The controller listens to document model/icon signals and refreshes the tree/icon cache. ## Clipboard architecture Clipboard support is intentionally extensible: - `services/clipboard.py`: system `QClipboard` and MIME/JSON handling. - `services/component_clipboard.py`: component payload serialization and ID remapping. - `controllers/clipboard_controller.py`: focus-based action router and handlers. `ClipboardHandler` is the base implementation for future editors. Add a graph-editor handler later by subclassing it and registering that handler in `application.py`. Text widgets use their native `copy()`, `cut()`, and `paste()` methods. Component clipboard data uses the custom BEdit MIME type and JSON; never use pickle or live object references. ## Icon editor conventions - Icons are GUI metadata stored in `document.metadata["icon_database"]`. - Shapes currently include rectangles, text, and lines. - Shape changes use the icon editor’s local undo stack. - Shapes are selectable, movable, resizable, pixel-snapped, and constrained to the icon scene. - Ports are separate 16×16 items: black for inputs and white for outputs. They can be moved but are not ordinary deletable/copyable shapes. - Colors are serialized as `#rrggbbaa`. - The icon scene is currently `(-64, -64, 128, 128)`. - The grid spacing is 8 scene pixels and is drawn only inside the scene rectangle. - Keep reusable widgets such as the RGBA color button independent of the icon editor. - Static icon previews belong in rendering utilities, not in the interactive editor scene. ## Actions and shortcut routing - Put visible actions in Designer menus/toolbars. - An action that only exists as a child object may not have an active shortcut; attach it to the relevant widget or place it in a menu/toolbar. - Route application-wide Copy/Cut/Paste by focused widget through `ClipboardController`. - Scope destructive shortcuts to the relevant widget where appropriate. - Always guard the operation itself even when an action is disabled for presentation. ## Verification The old test suite and its VS Code/packaging references were deliberately removed. Do not recreate a test suite unless asked. Use checks proportional to the change: ```sh .venv/bin/ruff check --ignore I001 path/to/changed_files.py ``` For Qt smoke checks in a headless environment: ```sh QT_QPA_PLATFORM=minimal QT_QPA_PLATFORMTHEME= QT_STYLE_OVERRIDE=Fusion .venv/bin/python ... ``` Prefer focused model, serialization, signal, command undo/redo, and offscreen rendering checks. Do not launch a GUI during verification unless explicitly requested or approved. ## Handoff expectations At the end of a task, report: - the outcome, - the files or subsystem changed, - relevant behavior and limitations, - checks that actually passed. Do not claim tests passed when only a lint or smoke check was run.