diff --git a/claude/integration-memory/MEMORY.md b/claude/integration-memory/MEMORY.md index f847e19..f121f53 100644 --- a/claude/integration-memory/MEMORY.md +++ b/claude/integration-memory/MEMORY.md @@ -17,7 +17,7 @@ ## Coding Style Preferences -- **NO STATIC FUNCTIONS in Unreal code.** Use class methods or namespace-scoped functions instead. This is a hard rule — the user has corrected this multiple times. +- **No FREE-FLOATING (file-scope) static functions in Unreal code.** Use class methods (incl. `static` member functions) or namespace-scoped functions instead. A `static` member function inside a class is fine — e.g. a Blueprint-callable factory. The rule is only against file-local `static` free functions. (Corrected 2026-05-26 after I misread this as banning all `static`.) - Prefer in-class member initializers (`int x_ = 0;` in the header) over explicit initialization in constructor bodies. When touching constructors, migrate toward this style. - Inline empty constructors/destructors in the header when possible. - Avoid ternary operator unless very concise (e.g., `x ? 1 : 0`). For longer expressions, use early-return `if` instead. @@ -46,15 +46,26 @@ - Blueprints in `/Game/Luprex/` use the `lx` prefix (e.g., `lxPlayerController`) and are loaded directly, not through the asset lookup system. - See `Source/Integration/AssetLookup.cpp` for the indexing logic. -## MCP / Blueprint Editing +## UE Wingman -- BlueprintMCP plugin is in `Plugins/BlueprintMCP/` (C++ plugin, editor-only). Listens on TCP port 9847. -- Python MCP bridge is `tools/mcp-bridge.py` (stdio transport, forwards to TCP port 9847). -- Blueprint text exports go to `Saved/BlueprintExports//` — includes both custom graph exports and Unreal's copy-format ASCII dump. +- UE Wingman is a command-line tool (no longer an MCP server). Plugin lives in `Plugins/UEWingman/`; CLI is `ue-wingman` (on PATH at `/home/jyelon/bin/ue-wingman`). +- Invoke directly via Bash. Subcommands are CamelCase, e.g. `ue-wingman Graph_Dump True`. +- Start by reading the manual: `ue-wingman Documentation_Manual`. Also useful: `Documentation_Commands` (concise list), `Documentation_Command ` (detailed help for one command). +- Common commands: `Blueprint_Dump`, `Graph_Dump`, `Details_Dump`, `Details_Set`, `GraphNode_ShowMenu`, `GraphNode_ChooseMenu`, `Variables_Add`/`Modify`/`Remove`, `TypeName_Search`. +- Fetcher path syntax: `/Game/,graph:,node:,pin:` (also `widget:`, `component:`, `levelblueprint:`, `structprop:`). FNames in paths use periods for spaces (e.g. `graph:Handle.Invalid.Lua.Command`, not `HandleInvalidLuaCommand`). Other marks `\"'(),.:;<=>&` use HTML entity escapes like ` `. +- ue-wingman is much faster than the LLM — batch multiple commands with `;` instead of running one at a time. + +## Project + +- [Eris addinfo intentionally removed](project_eris_addinfo_removed.md) — `luaG_runerror` no longer prefixes `file:line:`; traceback machinery handles location info ## Feedback - [UE Wingman testing mindset](feedback_wingman_testing.md) — flag tool friction during game work sessions - [Use mv for file renames](feedback_rename_with_mv.md) — mv + targeted edits, don't rewrite from memory - [LLDB formatter style — let lldb do the math](feedback_lldb_formatter_style.md) — typed SBValues, no raw pointer/byte math in Python -- [LLDB formatter style — no defensive IsValid checks](feedback_lldb_formatter_no_defensive_checks.md) — let invalid SBValues fail loudly; silent returns conceal bugs \ No newline at end of file +- [LLDB formatter style — no defensive IsValid checks](feedback_lldb_formatter_no_defensive_checks.md) — let invalid SBValues fail loudly; silent returns conceal bugs +- [C++ never depends on Blueprint](feedback_cpp_no_bp_dependency.md) — construct widget trees in C++; don't reference WBP assets from C++ +- [Prefer check() over silent-skip](feedback_check_over_silent_skip.md) — invariants use check(); silent continue/return hides bugs +- [Don't auto-build after every change](feedback_dont_auto_build.md) — only build when the user asks +- [Edit workspace template, not the generated file](feedback_workspace_template.md) — `Integration.code-workspace` is generated; edit `Integration.code-workspace.tpl.json` \ No newline at end of file diff --git a/claude/integration-memory/feedback_check_over_silent_skip.md b/claude/integration-memory/feedback_check_over_silent_skip.md new file mode 100644 index 0000000..cb76f2b --- /dev/null +++ b/claude/integration-memory/feedback_check_over_silent_skip.md @@ -0,0 +1,17 @@ +--- +name: Prefer check() over silent-skip for invariants +description: In C++ code, when a condition is an invariant that should always hold (not a legitimate filter), use check() instead of a silent continue/return that hides the bug +type: feedback +originSessionId: a2780d4f-894b-402a-8101-324052832606 +--- +When writing C++ code in this project, if a condition represents an **invariant** (something that must always be true based on how the code is structured), use `check()` to assert it — do **not** silently `continue`/`return`/guard past it. + +**Why:** Silent skips conceal bugs. If the invariant is ever violated, the code just mysteriously produces a shorter list, a missing widget, a zero count — with no signal that anything went wrong. `check()` fails loudly and makes the broken invariant visible and diagnosable. The user has articulated this as a general principle: "I am strongly against code that hides bugs by failing silently." + +**How to apply:** +- **Invariant → `check()`**: something that must hold given how the code is wired AND a violation would propagate silently (stored in a container, passed to a function that tolerates null, absorbed by a later filter). Example: pushing a potentially-null pointer into a TSet or TArray — segfault won't happen until much later. +- **Invariant about to be dereferenced → nothing**: if the very next line dereferences the pointer, a null will segfault on its own. That IS a loud failure. Don't add a `check()` just for style — the segfault is the check. Also don't add checks for things that were *just constructed* and cannot be null in any realistic scenario ("we just built this array"). +- **Legitimate filter → `if (...) continue;`**: a real business-logic condition that may or may not hold for different inputs. Example: filtering `Slots` to only those whose `Content` is a `UUserWidget` — other widget types are legitimate children, so skipping them is a filter, not hiding a bug. +- When in doubt, ask: "If this condition is false, is that a bug? AND will the bug propagate silently?" Only `check()` when BOTH are true. + +Related: [LLDB formatter style — no defensive IsValid checks](feedback_lldb_formatter_no_defensive_checks.md) is the same principle applied specifically to lldb SBValue chains. diff --git a/claude/integration-memory/feedback_cpp_no_bp_dependency.md b/claude/integration-memory/feedback_cpp_no_bp_dependency.md new file mode 100644 index 0000000..a4fba66 --- /dev/null +++ b/claude/integration-memory/feedback_cpp_no_bp_dependency.md @@ -0,0 +1,11 @@ +--- +name: C++ never depends on Blueprint, only the reverse +description: Never propose C++ code that loads/references Blueprint assets; dependency direction is strictly BP → C++ +type: feedback +originSessionId: a2780d4f-894b-402a-8101-324052832606 +--- +C++ code in this project must never depend on Blueprint assets. Dependencies flow one way only: Blueprints may depend on C++, never the reverse. + +**Why:** The user has stated this as a firm architectural principle. C++ that references BP assets (by soft class path, string, or otherwise) inverts the normal layering and creates fragile coupling to content. + +**How to apply:** When suggesting UMG patterns, do not propose solutions that involve C++ doing `CreateWidget` on a WBP class, loading a WBP via `FSoftClassPath`, or otherwise reaching from C++ into `/Game/...` content. For UMG work initiated from C++, construct widget trees programmatically in C++ (override `RebuildWidget`, manipulate `WidgetTree` directly). Blueprint subclasses of C++ widget classes are fine — that's BP depending on C++. diff --git a/claude/integration-memory/feedback_dont_auto_build.md b/claude/integration-memory/feedback_dont_auto_build.md new file mode 100644 index 0000000..d1ed28e --- /dev/null +++ b/claude/integration-memory/feedback_dont_auto_build.md @@ -0,0 +1,14 @@ +--- +name: Don't build after every code change +description: Don't automatically run build.py after every edit; wait for the user to ask for a build +type: feedback +originSessionId: a2780d4f-894b-402a-8101-324052832606 +--- +Do not run `build.py` (or any build command) after every code change. The user will explicitly ask for a build when they want one. + +**Why:** The user is iterating quickly and doesn't want to wait for builds between every small edit. Builds take ~10s and add noise to the conversation. The user will batch up several changes and ask for a build when they want to verify. + +**How to apply:** +- Make code edits and report them. Stop there. +- Only run `build.py c++` when the user explicitly asks ("build please", "build", "verify it compiles", etc.). +- Don't proactively build after a rename, refactor, or other "obviously needs verification" change. Trust the user to ask if they want it. diff --git a/claude/integration-memory/feedback_workspace_template.md b/claude/integration-memory/feedback_workspace_template.md new file mode 100644 index 0000000..235d915 --- /dev/null +++ b/claude/integration-memory/feedback_workspace_template.md @@ -0,0 +1,11 @@ +--- +name: Edit workspace template, not the generated file +description: Integration.code-workspace is generated; edit Integration.code-workspace.tpl.json instead +type: feedback +originSessionId: b0f1e20f-9463-4d0f-aead-52a71412214a +--- +`Integration.code-workspace` is a generated file. The source of truth is `Integration.code-workspace.tpl.json` at the project root. + +**Why:** Edits to the generated `.code-workspace` get blown away the next time the workspace is regenerated, silently losing the change. + +**How to apply:** Whenever a settings change needs to land in the VS Code workspace (e.g., `clangd.path`, `clangd.arguments`, file associations), edit `Integration.code-workspace.tpl.json`. Don't touch `Integration.code-workspace` directly. diff --git a/claude/integration-memory/project_eris_addinfo_removed.md b/claude/integration-memory/project_eris_addinfo_removed.md new file mode 100644 index 0000000..4c26eeb --- /dev/null +++ b/claude/integration-memory/project_eris_addinfo_removed.md @@ -0,0 +1,14 @@ +--- +name: project-eris-addinfo-removed +description: "In this project's Eris fork, ldebug.c's addinfo() is intentionally commented out (luaG_runerror no longer prepends file:line: to error messages)." +metadata: + node_type: memory + type: project + originSessionId: bf905462-91dc-4dab-9f49-f76bf9ed0c8e +--- + +In `luprex/ext/eris-master/src/ldebug.c`, the `addinfo` function is commented out, and `luaG_runerror` no longer calls it. This means stock Lua's `"file:line: "` prefix is NOT added to runtime error messages. + +**Why:** This project always appends a full traceback to errors via `traceback_pcall` / `traceback_coroutine` (in `luprex/cpp/core/traceback.cpp`). The traceback already shows file:line for every frame including the one that threw, so addinfo's prefix would be redundant. + +**How to apply:** Don't "fix" the commented-out addinfo. If a runtime error message looks bare (no leading `file:line:`), that's expected — the traceback machinery is responsible for location info, not the message itself. diff --git a/codex/config.toml b/codex/config.toml index 41d3570..dfdbc82 100644 --- a/codex/config.toml +++ b/codex/config.toml @@ -27,3 +27,4 @@ approval_mode = "approve" [tui.model_availability_nux] "gpt-5.5" = 2 + diff --git a/vscode/settings.json b/vscode/settings.json index 8b4a632..bf8bd9d 100644 --- a/vscode/settings.json +++ b/vscode/settings.json @@ -15,7 +15,7 @@ "editor.hover.delay": 1000, "editor.hover.sticky": false, "editor.fontFamily": "Cousine", - "workbench.colorTheme": "Default Light Modern", + "workbench.colorTheme": "Light Modern", "editor.autoClosingBrackets": "never", "editor.autoClosingOvertype": "never", "editor.autoClosingComments": "never", @@ -27,5 +27,13 @@ "editor.suggest.filterGraceful": false, "extensions.ignoreRecommendations": true, "diffEditor.renderSideBySide": false + "editor.inlineSuggest.suppressSuggestions": true, + "editor.quickSuggestions": { + "comments": "off", + "strings": "off", + "other": "off" + }, + "editor.parameterHints.enabled": false, + "editor.suggestOnTriggerCharacters": false }