# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Language Conventions - **Output / explanations:** Russian - **Code:** English - **Comments, commit messages:** Russian ## Commands ```bash # Build dotnet build # Run (starts TUI + HTTP MCP endpoint on port 5000) dotnet run --project LazyBear.MCP # Test MCP tool wiring (only needed after changing transport or tool registration) npx @modelcontextprotocol/inspector dotnet run --project LazyBear.MCP ``` There are **no test projects**. After making changes, run `dotnet build`. If MCP wiring changed (new tool, new module, transport changes), also run the inspector. Port is controlled via the `ASPNETCORE_URLS` environment variable (default `http://localhost:5000`). Ignore `launchSettings.json` — it shows a different port that is not used. ## Architecture LazyBear is a .NET 10 MCP server exposing Jira, Confluence, and Kubernetes integrations to AI clients. It runs in two simultaneous modes that share a single DI container: 1. **TUI (foreground)** — RazorConsole terminal UI (`App.razor`), owns the console, handles keyboard navigation 2. **HTTP MCP endpoint (background)** — `McpWebHostedService` runs as a hosted service, serves MCP tool calls on port 5000 Both share the same singletons: `ToolRegistryService`, `InMemoryLogSink`, `GlobalKeyboardService`, and the three client providers. ### Plugin System (IToolModule) Each integration implements `IToolModule` (in `Services/ToolRegistry/IToolModule.cs`) and declares its `ModuleName`, `ToolNames[]`, and `Description`. Tool classes are auto-discovered at startup via reflection using `WithToolsFromAssembly()` — classes are annotated with `[McpServerToolType]`, methods with `[McpServerTool]`. Registering a new module requires only: implement `IToolModule`, create tool classes with attributes, and add DI registration in `Program.cs`. ### ToolRegistryService Singleton that tracks enabled/disabled state for both modules and individual tools at runtime (no restart needed). Uses `ConcurrentDictionary` for thread safety. Fires `StateChanged` event on toggles; TUI components subscribe to re-render. Tool keys use the format `"ModuleName::ToolName"`. ### Provider Pattern Each client (`K8sClientProvider`, `JiraClientProvider`, `ConfluenceClientProvider`) is a lazy singleton. If initialization fails (missing config, unreachable endpoint), it captures an `InitializationError` string. **Tools return error strings instead of throwing exceptions** — this is intentional so MCP clients see the configuration issue gracefully. ### Logging `InMemoryLogSink` maintains a 500-entry circular `ConcurrentQueue`. All .NET logs flow through `InMemoryLoggerProvider` → sink → `OnLog` event → TUI Logs tab live view. ### TUI Keyboard Input `GlobalKeyboardService` (`TUI/GlobalKeyboardService.cs`) is the **single source of keyboard events** for the entire TUI. It runs a dedicated background thread with a blocking `Console.ReadKey(intercept: true)` — no polling. `App.razor` subscribes to `OnKeyPressed`, converts `ConsoleKeyInfo` to `KeyboardEventArgs`, and dispatches via `InvokeAsync`. Do **not** use `@onkeydown` on `