| name | Basic dev agent |
|---|---|
| description | Used for general purpose NodeDev development |
- You must always read the documentation files when they are related to your current task. They are described in the "Documentation" section of this document.
- You must always run the tests and make sure they are passing before you consider your job as completed, no matter how long you have been at the task or any following instruction to make it short or end the task early.
- CRITICAL: Disabling, removing, skipping, deleting, bypassing or converting to warnings ANY tests IS NOT ALLOWED and is not considered the right way of fixing a problematic test. The test must be functional and actually testing what it is intended to test. DO NOT REMOVE TESTS UNLESS EXPLICITLY INSTRUCTED TO DO SO BY THE USER.
- Document newly added content or concepts in this
.github/agents/basicAgent.agent.mdfile or any related documentation file. - When the user corrects major mistakes done during your development, document them in this file to ensure it is never done again.
- You must always install playwright BEFORE trying to run the tests. build the projects and install playwright. If you struggle (take multiple iterations to do it), document the steps you took in this file to make it easier next time.
- ALWAYS read the E2E testing documentation (
docs/e2e-testing.md) BEFORE making any changes to E2E tests. This documentation contains critical information about test patterns, selector strategies, and troubleshooting. - When encountering E2E test issues (timeouts, element not found, etc.), ALWAYS use the Playwright MCP tools to take screenshots and inspect the page state before assuming the test or functionality is broken. Use
playwright-browser_snapshotandplaywright-browser_take_screenshotto validate element visibility and page state.
- Always use C# nullable
- Prefer small polymorphic classes rather than big helper style classes
- Write many tests for any newly added feature, whether in the core as unit tests or in the UI as e2e tests
NodeDev is a visual programming environment built with Blazor and Blazor.Diagrams. It allows users to create software using a node-based visual interface instead of traditional text-based code. The system generates native IL code for near-native execution performance.
- NodeDev.Core: Core business logic, node definitions, graph management, type system, IL code generation, and debugging infrastructure (in
Debugger/folder) - NodeDev.Blazor: UI components built with Blazor (Razor components, diagrams, project explorer)
- NodeDev.Blazor.Server: Server-side Blazor hosting
- NodeDev.Blazor.MAUI: MAUI-based desktop application wrapper
- NodeDev.Tests: Unit tests for core functionality
- NodeDev.EndToEndTests: Playwright-based E2E tests with Reqnroll (SpecFlow successor)
- NodeDev.ScriptRunner: Console application that executes compiled user code as a separate process, serving as the target for the ICorDebug debugging infrastructure
The main UI consists of:
- AppBar: Top toolbar with project controls (New, Open, Save, Options, Run, Run with Debug)
- ProjectExplorer: Left panel showing project structure (classes, methods, properties)
- GraphCanvas: Central canvas where nodes are placed and connected
- ClassExplorer: Shows details of the currently selected class
- DebuggerConsolePanel: Bottom panel with tabs for Console Output and Debug Callbacks
- Uses Blazor.Diagrams library for visual node editing
- GraphNodeModel: Represents a node in the diagram (wraps Core.Node)
- GraphPortModel: Represents input/output ports on nodes
- GraphCanvas: Main component managing the diagram, node creation, and connections
- Flow Nodes: Control execution (Entry, Return, Branch, While, For, etc.) - have Exec connections
- Data Nodes: Compute values without flow (Math operations, comparisons) - no Exec connections
- Mixed Nodes: Both Exec and data (DeclareVariable, SetProperty, etc.)
- Generic Types: Automatically resolve based on connections (T, T1, T2 → concrete types)
- E2E tests use Playwright with Reqnroll for BDD-style scenarios
- Tests start a Blazor Server instance and automate browser interactions
- Components use
data-test-idattributes for test targeting - Mouse event sequences critical for drag operations: MoveAsync → DownAsync → MoveAsync(with steps) → UpAsync
Before running E2E tests, Playwright browsers must be installed:
-
Build the test project first:
dotnet build src/NodeDev.EndToEndTests/NodeDev.EndToEndTests.csproj
-
Install Playwright Chromium browser:
cd src/NodeDev.EndToEndTests pwsh bin/Debug/net10.0/playwright.ps1 install chromium -
The browser will be installed to
~/.cache/ms-playwright/
Important: Playwright must be reinstalled after:
- Cleaning the build output
- Updating the Playwright NuGet package
- Running tests in a fresh CI environment
Without Playwright installed, all E2E tests will fail with browser launch errors.
The debugger integration tests require the dbgshim library to be available. This is obtained automatically via the Microsoft.Diagnostics.DbgShim NuGet package which is referenced by NodeDev.Core.
How it works:
- The
Microsoft.Diagnostics.DbgShimNuGet package (v9.0.652701) is included as a dependency in NodeDev.Core - When the package is restored, it downloads platform-specific native libraries:
microsoft.diagnostics.dbgshim.linux-x64for Linux x64microsoft.diagnostics.dbgshim.win-x64for Windows x64- And other platform variants
- The
DbgShimResolverclass automatically finds the library in the NuGet packages cache
Location of dbgshim library:
- NuGet cache:
~/.nuget/packages/microsoft.diagnostics.dbgshim.linux-x64/[version]/runtimes/linux-x64/native/libdbgshim.so - Windows:
~/.nuget/packages/microsoft.diagnostics.dbgshim.win-x64/[version]/runtimes/win-x64/native/dbgshim.dll
Running the debugger tests:
# Build and restore packages
dotnet build src/NodeDev.Tests/NodeDev.Tests.csproj
# Run debugger tests
dotnet test src/NodeDev.Tests/NodeDev.Tests.csproj --filter "DebuggerCoreTests"The tests demonstrate:
- Finding dbgshim from the NuGet package
- Loading the dbgshim library
- Creating a NodeDev project with nodes
- Building the project
- Launching the process in suspended mode
- Registering for CLR runtime startup
- Enumerating CLRs in the target process
- Attaching to the process and obtaining ICorDebug interface
Detailed topic-specific documentation is maintained in the docs/ folder:
docs/e2e-testing.md- End-to-end testing patterns, node interaction, connection testing, and screenshot validationdocs/node-types-and-connections.md- Comprehensive guide to node types, connection system, port identification, and testing strategiesdocs/script-runner.md- ScriptRunner architecture, usage, and ICorDebug debugging infrastructure
NodeDev now supports "Hard Debugging" via the ICorDebug API (.NET's unmanaged debugging interface). This provides low-level debugging capabilities including:
- Process attachment and management
- Debug event callbacks (process creation, module loading, thread creation, etc.)
- Future support for breakpoints and step-through execution
Running with Debug: The UI provides two run modes:
- Run - Normal execution without debugger attachment
- Run with Debug - Executes with ICorDebug debugger attached
Important: "Run with Debug" requires successful debugger attachment. If attachment fails for any reason (DbgShim not found, CLR enumeration fails, etc.), the operation will fail with an error dialog showing the specific issue. There is no fallback to normal execution.
Debug State Management:
Project.IsHardDebugging- Boolean property indicating active debug sessionProject.DebuggedProcessId- Process ID of debugged process (null when not debugging)Project.HardDebugStateChanged- Observable stream for debug state changes (true when attached, false when detached)Project.DebugCallbacks- Observable stream ofDebugCallbackEventArgsfor all debug events
UI Visual Feedback:
- "Run with Debug" button changes color (warning) and shows PID when debugging
- Button is disabled during active debug session
- DebuggerConsolePanel shows two tabs:
- "Console Output" - Standard output from the program
- "Debug Callbacks" - Real-time debug events with timestamps
Implementation Pattern:
// Running with debug in Project.cs
try
{
var result = project.RunWithDebug(BuildOptions.Debug);
}
catch (InvalidOperationException ex)
{
// Handle debug attachment failure
// Show error dialog to user with ex.Message
Console.WriteLine($"Debug failed: {ex.Message}");
}
// Subscribing to debug callbacks
project.DebugCallbacks.Subscribe(callback => {
Console.WriteLine($"{callback.CallbackType}: {callback.Description}");
});
// Subscribing to debug state changes
project.HardDebugStateChanged.Subscribe(isDebugging => {
if (isDebugging)
Console.WriteLine("Debugging started");
else
Console.WriteLine("Debugging stopped");
});The debugging infrastructure is located in src/NodeDev.Core/Debugger/ and provides ICorDebug API access via the ClrDebug NuGet package:
- DbgShimResolver: Cross-platform resolution for the dbgshim library from NuGet packages or system paths
- DebugSessionEngine: Main debugging engine with process launch, attach, and callback handling
- ManagedDebuggerCallbacks: Implementation of ICorDebugManagedCallback interfaces via ClrDebug
- DebugEngineException: Custom exception type for debugging errors
- NodeBreakpointInfo: Maps nodes to their generated source code locations for breakpoint resolution
- BreakpointMappingInfo: Collection of all breakpoint information for a compiled project
Dependencies:
ClrDebug(v0.3.4): C# wrappers for the unmanaged ICorDebug APIMicrosoft.Diagnostics.DbgShim(v9.0.652701): Native dbgshim library for all platforms
NodeDev supports setting breakpoints on nodes during debugging. The system tracks node-to-source-line mappings during compilation:
Infrastructure:
- Node Marking: Nodes are marked with
BreakpointDecoration(only non-inlinable nodes support breakpoints) - Line Tracking:
RoslynGraphBuilder.BuildStatementsWithBreakpointTracking()tracks which source line each node generates - Compilation:
RoslynNodeClassCompilercollects all breakpoint mappings intoBreakpointMappingInfo - Storage: Project stores breakpoint mappings after build for use during debugging
- Debug Engine:
DebugSessionEnginereceives breakpoint mappings and attempts to set breakpoints after modules load
Implementation:
- ✅ Node breakpoint marking and persistence
- ✅ #line directives with virtual line numbers for stable mapping
- ✅ PDB sequence point reading for accurate IL offset resolution
- ✅ Breakpoint mapping storage in compilation results
- ✅ Debug engine infrastructure for breakpoint management
- ✅ Actual ICorDebug breakpoint setting with
ICorDebugFunction.CreateBreakpoint() - ✅ Execution pauses at breakpoints and resumes with Continue()
How It Works:
- UI allows toggling breakpoints on nodes (F9 or toolbar button)
- Breakpoints persist across save/load
- Compilation adds #line directives with virtual line numbers (10000, 11000, 12000...)
- PDB sequence points are read to map virtual lines to exact IL offsets
- Debug engine creates actual ICorDebug breakpoints at precise locations
- Execution pauses when breakpoints are hit
- User can resume with Continue()
NodeDev includes a separate console application called ScriptRunner that serves as the target process for debugging. This architecture supports "Hard Debugging" via the ICorDebug API.
Architecture:
- Host Process: The Visual IDE (NodeDev.Blazor.Server or NodeDev.Blazor.MAUI)
- Target Process: ScriptRunner - a separate console application that executes the user's compiled code
ScriptRunner Features:
- Accepts a DLL path as command-line argument
- Optional
--wait-for-debuggerflag to pause execution until debugger attaches - Loads assemblies using
Assembly.LoadFrom() - Finds and invokes entry points:
- Static
Program.Mainmethod (in any namespace) - Types implementing
IRunnableinterface (future extensibility)
- Static
- Wraps execution in try/catch blocks to print exceptions to console
- Proper exit code handling for CI/CD integration
Build System:
- ScriptRunner is automatically built with NodeDev.Core
- MSBuild targets copy ScriptRunner to the output directory of dependent projects
- The
Project.Run()method automatically locates and launches ScriptRunner - The
Project.RunWithDebug()method launches ScriptRunner and attaches debugger - The
Project.GetScriptRunnerPath()method returns the ScriptRunner location for debugging infrastructure