{"owner":"OrchardCMS","repo":"OrchardCore","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# Orchard Core - Agent Guidelines\n\nThis document provides instructions for LLM agents working with the Orchard Core codebase. It covers building, testing, and creating new features.\n\n## Project Overview\n\nOrchard Core is an open-source, modular, multi-tenant application framework and CMS for ASP.NET Core. It consists of:\n\n- **Orchard Core Framework**: An application framework for building modular, multi-tenant applications\n- **Orchard Core CMS**: A Web Content Management System built on top of the framework\n\n**Repository**: <https://github.com/OrchardCMS/OrchardCore>  \n**Documentation**: <https://docs.orchardcore.net/>\n\n## Prerequisites\n\n- **.NET SDK**: Version 10.0+ (see `global.json` for exact version requirements)\n- **Node.js**: Version 24.x LTS (for asset compilation)\n- **Yarn**: Version 4.x (package manager for frontend assets)\n\n## Building the Project\n\n### Command Line\n\n```bash\n# Navigate to the web project\ncd src/OrchardCore.Cms.Web\n\n# Run the application\ndotnet run\n\n# Or build with specific configuration\ndotnet build -c Debug -f net10.0\n```\n\n### Full Solution Build\n\n```bash\n# From repository root\ndotnet build OrchardCore.sln\n\n# Build with Release configuration\ndotnet build OrchardCore.sln -c Release\n```\n\n### Target Framework\n\nThe default target framework is `net10.0` as defined in `src/OrchardCore.Build/TargetFrameworks.props`.\n\n## Running the Application\n\n```bash\ncd src/OrchardCore.Cms.Web\ndotnet run -f net10.0\n```\n\nThe application will be available at `http://localhost:5000` (and `https://localhost:5001`).\n\n## Running Tests\n\n### Unit Tests\n\nUnit tests are located in the `test/` directory and use xUnit v3.\n\n```bash\n# Run all tests\ndotnet test\n\n# Run tests for a specific project\ndotnet test test/OrchardCore.Tests/OrchardCore.Tests.csproj\n\n# Run tests with a filter\ndotnet test --filter-method \"*.YourTest\"\n```\n\nArguments for tests:\n\n```bash\n--filter-class\n```\n\nRun all methods in a given test class. Pass one or more fully qualified type names (i.e.,\n'MyNamespace.MyClass' or 'MyNamespace.MyClass+InnerClass'). Wildcard '*' is supported at\nthe beginning and/or end of each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n```bash        \n--filter-method\n```\n\nRun a given test method. Pass one or more fully qualified method names (i.e.,\n'MyNamespace.MyClass.MyTestMethod'). Wildcard '*' is supported at the beginning and/or end\nof each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n\n### Functional Tests (Playwright)\n\nEnd-to-end tests are located in `test/OrchardCore.Tests.Functional/`.\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n### Automated Browser Testing (Playwright MCP)\n\nFor AI agents, the Playwright MCP (Model Context Protocol) provides automated browser testing capabilities:\n\n- **Setup**: Ensure the application is running at `http://localhost:5000`\n- **Navigation**: Use `mcp_playwright_browser_navigate` to navigate to pages\n- **Interactions**: Use tools like `mcp_playwright_browser_click`, `mcp_playwright_browser_type` for user actions\n- **Verification**: Use `mcp_playwright_browser_snapshot` to capture page state\n- **Console**: Use `mcp_playwright_browser_console_messages` to check for JavaScript errors\n\n**Example workflow:**\n1. Navigate to the application\n2. Complete setup wizard if needed\n3. Navigate to specific features (e.g., `/Admin/Media`)\n4. Interact with UI elements\n5. Verify console has no errors\n6. Capture screenshots or snapshots for validation\n\n### Test Organization\n\n- `test/OrchardCore.Tests/` - Main unit test project\n- `test/OrchardCore.Abstractions.Tests/` - Tests for abstractions\n- `test/OrchardCore.Tests.Functional/` - Playwright E2E functional tests\n- `test/OrchardCore.Tests.Modules/` - Test modules used by tests\n\n## Project Structure\n\n```\nOrchardCore/\n├── src/\n│   ├── OrchardCore/                    # Core framework libraries\n│   │   ├── OrchardCore/                # Main framework\n│   │   ├── OrchardCore.Abstractions/   # Core interfaces\n│   │   └── ...                         # Other abstractions\n│   ├── OrchardCore.Modules/            # Built-in modules\n│   ├── OrchardCore.Themes/             # Built-in themes\n│   ├── OrchardCore.Cms.Web/            # Main CMS web application\n│   └── docs/                           # Documentation source\n├── test/                               # Test projects\n└── .scripts/                           # Build and asset scripts\n```\n\n## Available Skills\n\nThe following skills are available in `.agents/skills/` for guided workflows:\n\n| Skill | Description | Use When |\n|-------|-------------|----------|\n| `orchardcore-module-creator` | Create new modules | Adding modules, content parts, fields, handlers |\n| `orchardcore-theme-creator` | Create new themes | Adding themes, layouts, frontend assets |\n| `orchardcore-recipe-creator` | Create setup recipes | Provisioning a tenant: features, themes, content, roles, settings |\n| `orchardcore-asset-manager` | Build/manage frontend assets | Modifying SCSS, JS, TS, Vue or troubleshooting the asset pipeline |\n| `orchardcore-admin-edit-views` | Build admin edit views | Creating/updating `*.Edit.cshtml` with `ocat-*` classes |\n| `orchardcore-data-migration` | Write data migrations | Altering content definitions, index tables, patching content items |\n| `orchardcore-display-management` | Control rendering | placement.json, drivers, shapes, zones, alternates, editor layouts |\n| `orchardcore-workflow-activity` | Custom workflow activities | New workflow task/event, outcomes, activity editor, input/output |\n| `orchardcore-query-indexing` | Queries & search indexing | SQL/Lucene queries, index profiles, index handlers, search |\n| `orchardcore-localization` | Localize apps & content | IStringLocalizer S/T/H, PO files, content translation, cultures |\n| `orchardcore-tenants` | Multi-tenancy | Shells, creating tenants, tenant scopes, feature profiles, isolation |\n| `orchardcore-unit-test` | Write & run tests | xUnit, SiteContext integration, Moq, Playwright functional |\n| `orchardcore-docs-writer` | Author docs | MkDocs pages, module README, nav, admonitions, redirects |\n| `orchardcore-tester` | Browser-based testing | Testing features via Playwright automation |\n| `orchardcore-nswag-regenerate` | Regenerate NSwag API clients | Updating `Services/OpenApiClient.cs`/`OpenApiClient.ts`, noisy NSwag regeneration diffs |\n\nThese skills provide step-by-step guidance, code templates, and references for common tasks.\n\n## Frontend Assets\n\n### Asset Management\n\nOrchard Core uses an asset manager for compiling SCSS, TypeScript, and JavaScript.\n\n```bash\n# Install Yarn\n\n# Install dependencies (from repository root)\ncorepack enable\nyarn\n\n# Build all assets including gulp\nyarn build\n```\n\n### Assets.json Configuration\n\nEach module with frontend assets needs an `Assets.json` file:\n\n```json\n[\n  {\n    \"action\": \"vite\",\n    \"name\": \"your-module\",\n    \"source\": \"Assets/\",\n    \"tags\": [\"js\", \"css\"]\n  }\n]\n```\n\n### Asset Dependencies (package.json)\n\n```json\n{\n  \"name\": \"@orchardcore/your-module\",\n  \"version\": \"1.0.0\",\n  \"dependencies\": {\n    \"vue\": \"3.5.13\",\n    \"bootstrap\": \"5.3.8\"\n  }\n}\n```\n\n## Content Management Patterns\n\nFor detailed patterns including Content Parts, Content Part Drivers, Content Fields, and more, see the `orchardcore-module-creator` skill in `.agents/skills/`.\n\n## Coding Conventions\n\n### General Guidelines\n\n- Follow [ASP.NET Core Engineering guidelines](https://github.com/dotnet/aspnetcore/wiki/Engineering-guidelines)\n- Use `sealed` for classes that should not be inherited\n- Use file-scoped namespaces\n- Prefer collection expressions (`[]`) over `new List<T>()`\n- Avoid use of primary constructors\n\n### Naming Conventions\n\n- Classes: `PascalCase`\n- Interfaces: `IPascalCase`\n- Methods: `PascalCase`\n- Properties: `PascalCase`\n- Private fields: `_camelCase`\n- Local variables: `camelCase`\n- Constants: `PascalCase`\n\n### Async Conventions\n\n- Suffix async methods with `Async`\n- Use `Task` or `ValueTask` return types\n\n### Code Analysis\n\nThe project uses:\n- StyleCop.Analyzers for style enforcement\n- `AnalysisLevel` set to `latest-Recommended`\n- Specific CA rules are suppressed (see `Directory.Build.props`)\n\n### Documentation\n\n- Update the canonical page under `src\\docs` whenever a change affects user-facing behavior, configuration, setup, public APIs, stereotypes, or extension points.\n- Add or update XML `<summary>` documentation for new or modified public interfaces, domain models, enums, and other public members that are part of the change.\n- Document each enum member individually when its behavior is relevant to users or downstream developers.\n- When XML documentation already exists, revise the existing block in place and keep `<param>` tags accurate and in signature order.\n\n## Database Patterns\n\n### YesSql Usage\n\nOrchard Core uses YesSql as its document database abstraction:\n\n```csharp\npublic class YourService\n{\n    private readonly ISession _session;\n\n    public YourService(ISession session)\n    {\n        _session = session;\n    }\n\n    public async Task<YourDocument> GetAsync(string id)\n    {\n        return await _session.Query<YourDocument, YourIndex>()\n            .Where(x => x.DocumentId == id)\n            .FirstOrDefaultAsync();\n    }\n\n    public async Task SaveAsync(YourDocument document)\n    {\n        await _session.SaveAsync(document);\n    }\n}\n```\n\n### Index Definition\n\n```csharp\npublic class YourIndex : MapIndex\n{\n    public string DocumentId { get; set; }\n    public string Name { get; set; }\n}\n\npublic class YourIndexProvider : IndexProvider<YourDocument>\n{\n    public override void Describe(DescribeContext<YourDocument> context)\n    {\n        context.For<YourIndex>()\n            .Map(doc => new YourIndex\n            {\n                DocumentId = doc.Id,\n                Name = doc.Name,\n            });\n    }\n}\n```\n\n## Testing Patterns\n\n### Unit Test Structure\n\nName test methods with the `{Action}_{Condition}_{ExpectedResult}` format, for example `Write_WithinLimit_Succeeds`.\n\n```csharp\nusing Xunit;\n\nnamespace OrchardCore.Tests.Modules.OrchardCore.YourModule;\n\npublic class YourServiceTests\n{\n    [Fact]\n    public async Task YourMethod_Condition_DoesSomething()\n    {\n        // Arrange\n        var service = new YourService();\n\n        // Act\n        var result = await service.YourMethodAsync();\n\n        // Assert\n        Assert.NotNull(result);\n    }\n\n    [Theory]\n    [InlineData(\"input1\", \"expected1\")]\n    [InlineData(\"input2\", \"expected2\")]\n    public void YourMethod_Input_ReturnsExpected(string input, string expected)\n    {\n        // Test implementation\n    }\n}\n```\n\n### Integration Test with Host\n\n```csharp\npublic class YourIntegrationTests : IClassFixture<OrchardTestFixture>\n{\n    private readonly OrchardTestFixture _fixture;\n\n    public YourIntegrationTests(OrchardTestFixture fixture)\n    {\n        _fixture = fixture;\n    }\n\n    [Fact]\n    public async Task Feature_DefaultRecipe_Works()\n    {\n        // Use _fixture to create test scenarios\n    }\n}\n```\n\n### Manual Testing\n\nFor browser-based manual testing using Playwright, see the `orchardcore-tester` skill in `.agents/skills/`.\n\n**Quick start:**\n```powershell\n# Build\ndotnet build src/OrchardCore.Cms.Web -c Debug -f net10.0\n\n# Generate/get port and start in background\n$port = if (Test-Path .orchardcore-port) { Get-Content .orchardcore-port } else { $p = Get-Random -Min 5000 -Max 6000; $p | Out-File .orchardcore-port -NoNewline; $p }\n$proc = Start-Process dotnet -ArgumentList \"run\",\"-f\",\"net10.0\",\"--no-build\",\"--urls\",\"http://localhost:$port\" -WorkingDirectory \"src/OrchardCore.Cms.Web\" -PassThru -NoNewWindow\n$proc.Id | Out-File .orchardcore-pid -NoNewline\n\n# URL: http://localhost:$port\n# Test credentials: admin / admin@test.com / Password1!\n\n# Stop when done\nStop-Process -Id (Get-Content .orchardcore-pid) -Force; Remove-Item .orchardcore-pid\n\n# Reset state: Remove-Item -Recurse -Force src/OrchardCore.Cms.Web/App_Data\n```\n\n**Debugging**: Check `src/OrchardCore.Cms.Web/App_Data/logs/orchard-log-{date}.log`\n\n### Functional Testing with Playwright\n\nCreate new functional tests under `test/OrchardCore.Tests.Functional/Tests/` following the existing C# test class patterns.\n\nRun the Playwright functional tests:\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n## Common Extension Points\n\n### Registering Services\n\n```csharp\n// In Startup.cs\nservices.AddScoped<IYourService, YourService>();\nservices.AddSingleton<IYourSingleton, YourSingleton>();\nservices.AddTransient<IYourTransient, YourTransient>();\n```\n\n### Event Handlers\n\n```csharp\npublic class YourContentHandler : ContentHandlerBase\n{\n    public override Task PublishedAsync(PublishContentContext context)\n    {\n        // Handle content published event\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Background Tasks\n\n```csharp\npublic class YourBackgroundTask : IBackgroundTask\n{\n    public Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)\n    {\n        // Background work implementation\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Navigation/Admin Menu\n\n```csharp\npublic sealed class AdminMenu : AdminNavigationProvider\n{\n    private readonly IStringLocalizer S;\n\n    public AdminMenu(IStringLocalizer<AdminMenu> localizer)\n    {\n        S = localizer;\n    }\n\n    protected override ValueTask BuildAsync(NavigationBuilder builder)\n    {\n        builder\n            .Add(S[\"Your Menu\"], menu => menu\n                .Add(S[\"Your Item\"], S[\"Your Item\"], item => item\n                    .Action(\"Index\", \"Admin\", \"OrchardCore.YourModule\")\n                    .Permission(YourPermissions.ManageYourFeature)\n                    .LocalNav()\n                )\n            );\n\n        return ValueTask.CompletedTask;\n    }\n}\n```\n\n## Debugging Tips\n\n1. **Enable detailed errors** in development by setting `ASPNETCORE_ENVIRONMENT=Development`\n2. **Check tenant logs** in `App_Data/Sites/{TenantName}/logs/`\n3. **Use MiniProfiler** module for performance analysis\n4. **Enable SQL logging** by configuring YesSql logging\n\n## Pull Request Guidelines\n\n1. Follow existing code style and conventions\n2. Include unit tests for new functionality\n3. Update the canonical documentation page when adding or changing user-facing features, public APIs, configuration, stereotypes, or extension points, and keep the docs aligned with the shipped code and behavior\n4. Run asset build if modifying CSS/JS: `yarn build`\n5. Ensure all tests pass: `dotnet test`\n6. Link related GitHub issues using `Fixes #IssueId`\n7. Add release notes for significant changes in `src/docs/releases/`, but do not rely on release notes as the only documentation for a feature; release notes describe what changed, while the canonical docs describe the current behavior without transitional or versioned wording\n\n## Useful Commands\n\n```bash\n# Restore packages\ndotnet restore\n\n# Clean build artifacts\ndotnet clean\n\n# Run\ndotnet run --project src/OrchardCore.Cms.Web\n\n# Build assets\nyarn build\n\n# Lint JavaScript/TypeScript\nyarn lint\n\n# Type check Vue/TypeScript\nyarn check\n```\n\n## Resources\n\n- [Documentation](https://docs.orchardcore.net/)\n- [Contributing Guide](https://docs.orchardcore.net/en/latest/contributing/)\n- [Discord Community](https://orchardcore.net/discord)\n- [Issue Tracker](https://github.com/OrchardCMS/OrchardCore/issues)\n- [API Reference](https://docs.orchardcore.net/en/latest/reference/)\n\n## Admin Edit View Conventions\n\nWhen creating or updating Orchard Core admin edit views, always use the `ocat-*` admin theme classes so the UI stays consistent across the site and works with custom admin theme overrides.\n\nThis applies to admin-facing Razor edit views such as:\n\n- `*.Edit.cshtml`\n- `*.Fields.Edit.cshtml`\n- Admin editor templates rendered in the admin theme\n\n### Required patterns\n\n| Scenario | Required structure |\n|---|---|\n| Standard admin field row (default for all inputs) | `ocat-wrapper` + `ocat-label` + `ocat-end` |\n| Required field label | `ocat-label ocat-label-required` |\n| Checkbox or toggle with no left-column label | `ocat-wrapper` + `ocat-end-offset` |\n| Standalone alert, notice, or section headline inside an edit form | `ocat-wrapper` + `ocat-end-offset` |\n| Limited-width row **only** for `type=\"number\"` inputs or when the user explicitly requests compact width | `ocat-limited-wrapper` + `ocat-label` + `ocat-limited` |\n\n> **Default rule:** Always use the standard `ocat-wrapper` + `ocat-label` + `ocat-end` pattern unless the input is a `type=\"number\"` field or the user explicitly asks for limited/compact width.\n\n### Standard field example\n\n```cshtml\n<div class=\"ocat-wrapper\" asp-validation-class-for=\"DisplayText\">\n    <label asp-for=\"DisplayText\" class=\"ocat-label\">@T[\"Display text\"]</label>\n    <div class=\"ocat-end\">\n        <input asp-for=\"DisplayText\" class=\"form-control\" />\n        <span asp-validation-for=\"DisplayText\"></span>\n        <span class=\"hint\">@T[\"Shown to editors in the admin UI.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field example (number inputs)\n\n```cshtml\n<div class=\"ocat-limited-wrapper\" asp-validation-class-for=\"PageSize\">\n    <label asp-for=\"PageSize\" class=\"ocat-label\">@T[\"Page size\"]</label>\n    <div class=\"ocat-limited\">\n        <input asp-for=\"PageSize\" type=\"number\" class=\"form-control\" />\n        <span asp-validation-for=\"PageSize\"></span>\n        <span class=\"hint\">@T[\"The default page size.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field inside a content field or content part wrapper\n\nIf the row also needs Orchard-specific wrapper classes such as `field-wrapper-*` or `content-part-wrapper-*`, keep the outer `ocat-wrapper` and place the compact control inside `ocat-end`:\n\n```cshtml\n<div class=\"ocat-wrapper field-wrapper @($\"field-wrapper-{Model.PartFieldDefinition.PartDefinition.Name.HtmlClassify()}-{Model.PartFieldDefinition.Name.HtmlClassify()}\")\">\n    <label asp-for=\"Value\" class=\"ocat-label\">@T[\"Value\"]</label>\n    <div class=\"ocat-end\">\n        <div class=\"ocat-limited-wrapper\">\n            <div class=\"ocat-limited\">\n                <input asp-for=\"Value\" class=\"form-control\" />\n                <span asp-validation-for=\"Value\"></span>\n            </div>\n        </div>\n        <span class=\"hint\">@T[\"Keeps a compact editor width without losing the field wrapper row.\"]</span>\n    </div>\n</div>\n```\n\n### Standalone alert or headline row\n\nUse `ocat-end-offset` for alerts, notices, legends, and headings that belong to the form but do not have a left-column label:\n\n```cshtml\n<div class=\"ocat-wrapper\">\n    <div class=\"ocat-end-offset\">\n        <h5>@T[\"Section heading\"]</h5>\n        <div class=\"alert alert-warning\" role=\"alert\">\n            @T[\"Important guidance for this form section.\"]\n        </div>\n    </div>\n</div>\n```\n\n### Avoid\n\n- `mb-3`, `form-group`, or `form-label` as the row layout pattern\n- Legacy helper methods such as `@Orchard.GetWrapperClasses()` or `@Orchard.GetLimitedWidthWrapperClasses()`\n- Using `ocat-limited-wrapper` for text inputs, selects, paths, IDs, or other non-number fields unless the user explicitly requests compact width\n- Mixing `ocat-end` and `ocat-end-offset` in the same row; choose exactly one based on whether the row has a left-column label\n"},"files":{"AGENTS.md":"# Orchard Core - Agent Guidelines\n\nThis document provides instructions for LLM agents working with the Orchard Core codebase. It covers building, testing, and creating new features.\n\n## Project Overview\n\nOrchard Core is an open-source, modular, multi-tenant application framework and CMS for ASP.NET Core. It consists of:\n\n- **Orchard Core Framework**: An application framework for building modular, multi-tenant applications\n- **Orchard Core CMS**: A Web Content Management System built on top of the framework\n\n**Repository**: <https://github.com/OrchardCMS/OrchardCore>  \n**Documentation**: <https://docs.orchardcore.net/>\n\n## Prerequisites\n\n- **.NET SDK**: Version 10.0+ (see `global.json` for exact version requirements)\n- **Node.js**: Version 24.x LTS (for asset compilation)\n- **Yarn**: Version 4.x (package manager for frontend assets)\n\n## Building the Project\n\n### Command Line\n\n```bash\n# Navigate to the web project\ncd src/OrchardCore.Cms.Web\n\n# Run the application\ndotnet run\n\n# Or build with specific configuration\ndotnet build -c Debug -f net10.0\n```\n\n### Full Solution Build\n\n```bash\n# From repository root\ndotnet build OrchardCore.sln\n\n# Build with Release configuration\ndotnet build OrchardCore.sln -c Release\n```\n\n### Target Framework\n\nThe default target framework is `net10.0` as defined in `src/OrchardCore.Build/TargetFrameworks.props`.\n\n## Running the Application\n\n```bash\ncd src/OrchardCore.Cms.Web\ndotnet run -f net10.0\n```\n\nThe application will be available at `http://localhost:5000` (and `https://localhost:5001`).\n\n## Running Tests\n\n### Unit Tests\n\nUnit tests are located in the `test/` directory and use xUnit v3.\n\n```bash\n# Run all tests\ndotnet test\n\n# Run tests for a specific project\ndotnet test test/OrchardCore.Tests/OrchardCore.Tests.csproj\n\n# Run tests with a filter\ndotnet test --filter-method \"*.YourTest\"\n```\n\nArguments for tests:\n\n```bash\n--filter-class\n```\n\nRun all methods in a given test class. Pass one or more fully qualified type names (i.e.,\n'MyNamespace.MyClass' or 'MyNamespace.MyClass+InnerClass'). Wildcard '*' is supported at\nthe beginning and/or end of each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n```bash        \n--filter-method\n```\n\nRun a given test method. Pass one or more fully qualified method names (i.e.,\n'MyNamespace.MyClass.MyTestMethod'). Wildcard '*' is supported at the beginning and/or end\nof each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n\n### Functional Tests (Playwright)\n\nEnd-to-end tests are located in `test/OrchardCore.Tests.Functional/`.\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n### Automated Browser Testing (Playwright MCP)\n\nFor AI agents, the Playwright MCP (Model Context Protocol) provides automated browser testing capabilities:\n\n- **Setup**: Ensure the application is running at `http://localhost:5000`\n- **Navigation**: Use `mcp_playwright_browser_navigate` to navigate to pages\n- **Interactions**: Use tools like `mcp_playwright_browser_click`, `mcp_playwright_browser_type` for user actions\n- **Verification**: Use `mcp_playwright_browser_snapshot` to capture page state\n- **Console**: Use `mcp_playwright_browser_console_messages` to check for JavaScript errors\n\n**Example workflow:**\n1. Navigate to the application\n2. Complete setup wizard if needed\n3. Navigate to specific features (e.g., `/Admin/Media`)\n4. Interact with UI elements\n5. Verify console has no errors\n6. Capture screenshots or snapshots for validation\n\n### Test Organization\n\n- `test/OrchardCore.Tests/` - Main unit test project\n- `test/OrchardCore.Abstractions.Tests/` - Tests for abstractions\n- `test/OrchardCore.Tests.Functional/` - Playwright E2E functional tests\n- `test/OrchardCore.Tests.Modules/` - Test modules used by tests\n\n## Project Structure\n\n```\nOrchardCore/\n├── src/\n│   ├── OrchardCore/                    # Core framework libraries\n│   │   ├── OrchardCore/                # Main framework\n│   │   ├── OrchardCore.Abstractions/   # Core interfaces\n│   │   └── ...                         # Other abstractions\n│   ├── OrchardCore.Modules/            # Built-in modules\n│   ├── OrchardCore.Themes/             # Built-in themes\n│   ├── OrchardCore.Cms.Web/            # Main CMS web application\n│   └── docs/                           # Documentation source\n├── test/                               # Test projects\n└── .scripts/                           # Build and asset scripts\n```\n\n## Available Skills\n\nThe following skills are available in `.agents/skills/` for guided workflows:\n\n| Skill | Description | Use When |\n|-------|-------------|----------|\n| `orchardcore-module-creator` | Create new modules | Adding modules, content parts, fields, handlers |\n| `orchardcore-theme-creator` | Create new themes | Adding themes, layouts, frontend assets |\n| `orchardcore-recipe-creator` | Create setup recipes | Provisioning a tenant: features, themes, content, roles, settings |\n| `orchardcore-asset-manager` | Build/manage frontend assets | Modifying SCSS, JS, TS, Vue or troubleshooting the asset pipeline |\n| `orchardcore-admin-edit-views` | Build admin edit views | Creating/updating `*.Edit.cshtml` with `ocat-*` classes |\n| `orchardcore-data-migration` | Write data migrations | Altering content definitions, index tables, patching content items |\n| `orchardcore-display-management` | Control rendering | placement.json, drivers, shapes, zones, alternates, editor layouts |\n| `orchardcore-workflow-activity` | Custom workflow activities | New workflow task/event, outcomes, activity editor, input/output |\n| `orchardcore-query-indexing` | Queries & search indexing | SQL/Lucene queries, index profiles, index handlers, search |\n| `orchardcore-localization` | Localize apps & content | IStringLocalizer S/T/H, PO files, content translation, cultures |\n| `orchardcore-tenants` | Multi-tenancy | Shells, creating tenants, tenant scopes, feature profiles, isolation |\n| `orchardcore-unit-test` | Write & run tests | xUnit, SiteContext integration, Moq, Playwright functional |\n| `orchardcore-docs-writer` | Author docs | MkDocs pages, module README, nav, admonitions, redirects |\n| `orchardcore-tester` | Browser-based testing | Testing features via Playwright automation |\n| `orchardcore-nswag-regenerate` | Regenerate NSwag API clients | Updating `Services/OpenApiClient.cs`/`OpenApiClient.ts`, noisy NSwag regeneration diffs |\n\nThese skills provide step-by-step guidance, code templates, and references for common tasks.\n\n## Frontend Assets\n\n### Asset Management\n\nOrchard Core uses an asset manager for compiling SCSS, TypeScript, and JavaScript.\n\n```bash\n# Install Yarn\n\n# Install dependencies (from repository root)\ncorepack enable\nyarn\n\n# Build all assets including gulp\nyarn build\n```\n\n### Assets.json Configuration\n\nEach module with frontend assets needs an `Assets.json` file:\n\n```json\n[\n  {\n    \"action\": \"vite\",\n    \"name\": \"your-module\",\n    \"source\": \"Assets/\",\n    \"tags\": [\"js\", \"css\"]\n  }\n]\n```\n\n### Asset Dependencies (package.json)\n\n```json\n{\n  \"name\": \"@orchardcore/your-module\",\n  \"version\": \"1.0.0\",\n  \"dependencies\": {\n    \"vue\": \"3.5.13\",\n    \"bootstrap\": \"5.3.8\"\n  }\n}\n```\n\n## Content Management Patterns\n\nFor detailed patterns including Content Parts, Content Part Drivers, Content Fields, and more, see the `orchardcore-module-creator` skill in `.agents/skills/`.\n\n## Coding Conventions\n\n### General Guidelines\n\n- Follow [ASP.NET Core Engineering guidelines](https://github.com/dotnet/aspnetcore/wiki/Engineering-guidelines)\n- Use `sealed` for classes that should not be inherited\n- Use file-scoped namespaces\n- Prefer collection expressions (`[]`) over `new List<T>()`\n- Avoid use of primary constructors\n\n### Naming Conventions\n\n- Classes: `PascalCase`\n- Interfaces: `IPascalCase`\n- Methods: `PascalCase`\n- Properties: `PascalCase`\n- Private fields: `_camelCase`\n- Local variables: `camelCase`\n- Constants: `PascalCase`\n\n### Async Conventions\n\n- Suffix async methods with `Async`\n- Use `Task` or `ValueTask` return types\n\n### Code Analysis\n\nThe project uses:\n- StyleCop.Analyzers for style enforcement\n- `AnalysisLevel` set to `latest-Recommended`\n- Specific CA rules are suppressed (see `Directory.Build.props`)\n\n### Documentation\n\n- Update the canonical page under `src\\docs` whenever a change affects user-facing behavior, configuration, setup, public APIs, stereotypes, or extension points.\n- Add or update XML `<summary>` documentation for new or modified public interfaces, domain models, enums, and other public members that are part of the change.\n- Document each enum member individually when its behavior is relevant to users or downstream developers.\n- When XML documentation already exists, revise the existing block in place and keep `<param>` tags accurate and in signature order.\n\n## Database Patterns\n\n### YesSql Usage\n\nOrchard Core uses YesSql as its document database abstraction:\n\n```csharp\npublic class YourService\n{\n    private readonly ISession _session;\n\n    public YourService(ISession session)\n    {\n        _session = session;\n    }\n\n    public async Task<YourDocument> GetAsync(string id)\n    {\n        return await _session.Query<YourDocument, YourIndex>()\n            .Where(x => x.DocumentId == id)\n            .FirstOrDefaultAsync();\n    }\n\n    public async Task SaveAsync(YourDocument document)\n    {\n        await _session.SaveAsync(document);\n    }\n}\n```\n\n### Index Definition\n\n```csharp\npublic class YourIndex : MapIndex\n{\n    public string DocumentId { get; set; }\n    public string Name { get; set; }\n}\n\npublic class YourIndexProvider : IndexProvider<YourDocument>\n{\n    public override void Describe(DescribeContext<YourDocument> context)\n    {\n        context.For<YourIndex>()\n            .Map(doc => new YourIndex\n            {\n                DocumentId = doc.Id,\n                Name = doc.Name,\n            });\n    }\n}\n```\n\n## Testing Patterns\n\n### Unit Test Structure\n\nName test methods with the `{Action}_{Condition}_{ExpectedResult}` format, for example `Write_WithinLimit_Succeeds`.\n\n```csharp\nusing Xunit;\n\nnamespace OrchardCore.Tests.Modules.OrchardCore.YourModule;\n\npublic class YourServiceTests\n{\n    [Fact]\n    public async Task YourMethod_Condition_DoesSomething()\n    {\n        // Arrange\n        var service = new YourService();\n\n        // Act\n        var result = await service.YourMethodAsync();\n\n        // Assert\n        Assert.NotNull(result);\n    }\n\n    [Theory]\n    [InlineData(\"input1\", \"expected1\")]\n    [InlineData(\"input2\", \"expected2\")]\n    public void YourMethod_Input_ReturnsExpected(string input, string expected)\n    {\n        // Test implementation\n    }\n}\n```\n\n### Integration Test with Host\n\n```csharp\npublic class YourIntegrationTests : IClassFixture<OrchardTestFixture>\n{\n    private readonly OrchardTestFixture _fixture;\n\n    public YourIntegrationTests(OrchardTestFixture fixture)\n    {\n        _fixture = fixture;\n    }\n\n    [Fact]\n    public async Task Feature_DefaultRecipe_Works()\n    {\n        // Use _fixture to create test scenarios\n    }\n}\n```\n\n### Manual Testing\n\nFor browser-based manual testing using Playwright, see the `orchardcore-tester` skill in `.agents/skills/`.\n\n**Quick start:**\n```powershell\n# Build\ndotnet build src/OrchardCore.Cms.Web -c Debug -f net10.0\n\n# Generate/get port and start in background\n$port = if (Test-Path .orchardcore-port) { Get-Content .orchardcore-port } else { $p = Get-Random -Min 5000 -Max 6000; $p | Out-File .orchardcore-port -NoNewline; $p }\n$proc = Start-Process dotnet -ArgumentList \"run\",\"-f\",\"net10.0\",\"--no-build\",\"--urls\",\"http://localhost:$port\" -WorkingDirectory \"src/OrchardCore.Cms.Web\" -PassThru -NoNewWindow\n$proc.Id | Out-File .orchardcore-pid -NoNewline\n\n# URL: http://localhost:$port\n# Test credentials: admin / admin@test.com / Password1!\n\n# Stop when done\nStop-Process -Id (Get-Content .orchardcore-pid) -Force; Remove-Item .orchardcore-pid\n\n# Reset state: Remove-Item -Recurse -Force src/OrchardCore.Cms.Web/App_Data\n```\n\n**Debugging**: Check `src/OrchardCore.Cms.Web/App_Data/logs/orchard-log-{date}.log`\n\n### Functional Testing with Playwright\n\nCreate new functional tests under `test/OrchardCore.Tests.Functional/Tests/` following the existing C# test class patterns.\n\nRun the Playwright functional tests:\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n## Common Extension Points\n\n### Registering Services\n\n```csharp\n// In Startup.cs\nservices.AddScoped<IYourService, YourService>();\nservices.AddSingleton<IYourSingleton, YourSingleton>();\nservices.AddTransient<IYourTransient, YourTransient>();\n```\n\n### Event Handlers\n\n```csharp\npublic class YourContentHandler : ContentHandlerBase\n{\n    public override Task PublishedAsync(PublishContentContext context)\n    {\n        // Handle content published event\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Background Tasks\n\n```csharp\npublic class YourBackgroundTask : IBackgroundTask\n{\n    public Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)\n    {\n        // Background work implementation\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Navigation/Admin Menu\n\n```csharp\npublic sealed class AdminMenu : AdminNavigationProvider\n{\n    private readonly IStringLocalizer S;\n\n    public AdminMenu(IStringLocalizer<AdminMenu> localizer)\n    {\n        S = localizer;\n    }\n\n    protected override ValueTask BuildAsync(NavigationBuilder builder)\n    {\n        builder\n            .Add(S[\"Your Menu\"], menu => menu\n                .Add(S[\"Your Item\"], S[\"Your Item\"], item => item\n                    .Action(\"Index\", \"Admin\", \"OrchardCore.YourModule\")\n                    .Permission(YourPermissions.ManageYourFeature)\n                    .LocalNav()\n                )\n            );\n\n        return ValueTask.CompletedTask;\n    }\n}\n```\n\n## Debugging Tips\n\n1. **Enable detailed errors** in development by setting `ASPNETCORE_ENVIRONMENT=Development`\n2. **Check tenant logs** in `App_Data/Sites/{TenantName}/logs/`\n3. **Use MiniProfiler** module for performance analysis\n4. **Enable SQL logging** by configuring YesSql logging\n\n## Pull Request Guidelines\n\n1. Follow existing code style and conventions\n2. Include unit tests for new functionality\n3. Update the canonical documentation page when adding or changing user-facing features, public APIs, configuration, stereotypes, or extension points, and keep the docs aligned with the shipped code and behavior\n4. Run asset build if modifying CSS/JS: `yarn build`\n5. Ensure all tests pass: `dotnet test`\n6. Link related GitHub issues using `Fixes #IssueId`\n7. Add release notes for significant changes in `src/docs/releases/`, but do not rely on release notes as the only documentation for a feature; release notes describe what changed, while the canonical docs describe the current behavior without transitional or versioned wording\n\n## Useful Commands\n\n```bash\n# Restore packages\ndotnet restore\n\n# Clean build artifacts\ndotnet clean\n\n# Run\ndotnet run --project src/OrchardCore.Cms.Web\n\n# Build assets\nyarn build\n\n# Lint JavaScript/TypeScript\nyarn lint\n\n# Type check Vue/TypeScript\nyarn check\n```\n\n## Resources\n\n- [Documentation](https://docs.orchardcore.net/)\n- [Contributing Guide](https://docs.orchardcore.net/en/latest/contributing/)\n- [Discord Community](https://orchardcore.net/discord)\n- [Issue Tracker](https://github.com/OrchardCMS/OrchardCore/issues)\n- [API Reference](https://docs.orchardcore.net/en/latest/reference/)\n\n## Admin Edit View Conventions\n\nWhen creating or updating Orchard Core admin edit views, always use the `ocat-*` admin theme classes so the UI stays consistent across the site and works with custom admin theme overrides.\n\nThis applies to admin-facing Razor edit views such as:\n\n- `*.Edit.cshtml`\n- `*.Fields.Edit.cshtml`\n- Admin editor templates rendered in the admin theme\n\n### Required patterns\n\n| Scenario | Required structure |\n|---|---|\n| Standard admin field row (default for all inputs) | `ocat-wrapper` + `ocat-label` + `ocat-end` |\n| Required field label | `ocat-label ocat-label-required` |\n| Checkbox or toggle with no left-column label | `ocat-wrapper` + `ocat-end-offset` |\n| Standalone alert, notice, or section headline inside an edit form | `ocat-wrapper` + `ocat-end-offset` |\n| Limited-width row **only** for `type=\"number\"` inputs or when the user explicitly requests compact width | `ocat-limited-wrapper` + `ocat-label` + `ocat-limited` |\n\n> **Default rule:** Always use the standard `ocat-wrapper` + `ocat-label` + `ocat-end` pattern unless the input is a `type=\"number\"` field or the user explicitly asks for limited/compact width.\n\n### Standard field example\n\n```cshtml\n<div class=\"ocat-wrapper\" asp-validation-class-for=\"DisplayText\">\n    <label asp-for=\"DisplayText\" class=\"ocat-label\">@T[\"Display text\"]</label>\n    <div class=\"ocat-end\">\n        <input asp-for=\"DisplayText\" class=\"form-control\" />\n        <span asp-validation-for=\"DisplayText\"></span>\n        <span class=\"hint\">@T[\"Shown to editors in the admin UI.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field example (number inputs)\n\n```cshtml\n<div class=\"ocat-limited-wrapper\" asp-validation-class-for=\"PageSize\">\n    <label asp-for=\"PageSize\" class=\"ocat-label\">@T[\"Page size\"]</label>\n    <div class=\"ocat-limited\">\n        <input asp-for=\"PageSize\" type=\"number\" class=\"form-control\" />\n        <span asp-validation-for=\"PageSize\"></span>\n        <span class=\"hint\">@T[\"The default page size.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field inside a content field or content part wrapper\n\nIf the row also needs Orchard-specific wrapper classes such as `field-wrapper-*` or `content-part-wrapper-*`, keep the outer `ocat-wrapper` and place the compact control inside `ocat-end`:\n\n```cshtml\n<div class=\"ocat-wrapper field-wrapper @($\"field-wrapper-{Model.PartFieldDefinition.PartDefinition.Name.HtmlClassify()}-{Model.PartFieldDefinition.Name.HtmlClassify()}\")\">\n    <label asp-for=\"Value\" class=\"ocat-label\">@T[\"Value\"]</label>\n    <div class=\"ocat-end\">\n        <div class=\"ocat-limited-wrapper\">\n            <div class=\"ocat-limited\">\n                <input asp-for=\"Value\" class=\"form-control\" />\n                <span asp-validation-for=\"Value\"></span>\n            </div>\n        </div>\n        <span class=\"hint\">@T[\"Keeps a compact editor width without losing the field wrapper row.\"]</span>\n    </div>\n</div>\n```\n\n### Standalone alert or headline row\n\nUse `ocat-end-offset` for alerts, notices, legends, and headings that belong to the form but do not have a left-column label:\n\n```cshtml\n<div class=\"ocat-wrapper\">\n    <div class=\"ocat-end-offset\">\n        <h5>@T[\"Section heading\"]</h5>\n        <div class=\"alert alert-warning\" role=\"alert\">\n            @T[\"Important guidance for this form section.\"]\n        </div>\n    </div>\n</div>\n```\n\n### Avoid\n\n- `mb-3`, `form-group`, or `form-label` as the row layout pattern\n- Legacy helper methods such as `@Orchard.GetWrapperClasses()` or `@Orchard.GetLimitedWidthWrapperClasses()`\n- Using `ocat-limited-wrapper` for text inputs, selects, paths, IDs, or other non-number fields unless the user explicitly requests compact width\n- Mixing `ocat-end` and `ocat-end-offset` in the same row; choose exactly one based on whether the row has a left-column label\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Orchard Core - Agent Guidelines\n\nThis document provides instructions for LLM agents working with the Orchard Core codebase. It covers building, testing, and creating new features.\n\n## Project Overview\n\nOrchard Core is an open-source, modular, multi-tenant application framework and CMS for ASP.NET Core. It consists of:\n\n- **Orchard Core Framework**: An application framework for building modular, multi-tenant applications\n- **Orchard Core CMS**: A Web Content Management System built on top of the framework\n\n**Repository**: <https://github.com/OrchardCMS/OrchardCore>  \n**Documentation**: <https://docs.orchardcore.net/>\n\n## Prerequisites\n\n- **.NET SDK**: Version 10.0+ (see `global.json` for exact version requirements)\n- **Node.js**: Version 24.x LTS (for asset compilation)\n- **Yarn**: Version 4.x (package manager for frontend assets)\n\n## Building the Project\n\n### Command Line\n\n```bash\n# Navigate to the web project\ncd src/OrchardCore.Cms.Web\n\n# Run the application\ndotnet run\n\n# Or build with specific configuration\ndotnet build -c Debug -f net10.0\n```\n\n### Full Solution Build\n\n```bash\n# From repository root\ndotnet build OrchardCore.sln\n\n# Build with Release configuration\ndotnet build OrchardCore.sln -c Release\n```\n\n### Target Framework\n\nThe default target framework is `net10.0` as defined in `src/OrchardCore.Build/TargetFrameworks.props`.\n\n## Running the Application\n\n```bash\ncd src/OrchardCore.Cms.Web\ndotnet run -f net10.0\n```\n\nThe application will be available at `http://localhost:5000` (and `https://localhost:5001`).\n\n## Running Tests\n\n### Unit Tests\n\nUnit tests are located in the `test/` directory and use xUnit v3.\n\n```bash\n# Run all tests\ndotnet test\n\n# Run tests for a specific project\ndotnet test test/OrchardCore.Tests/OrchardCore.Tests.csproj\n\n# Run tests with a filter\ndotnet test --filter-method \"*.YourTest\"\n```\n\nArguments for tests:\n\n```bash\n--filter-class\n```\n\nRun all methods in a given test class. Pass one or more fully qualified type names (i.e.,\n'MyNamespace.MyClass' or 'MyNamespace.MyClass+InnerClass'). Wildcard '*' is supported at\nthe beginning and/or end of each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n```bash        \n--filter-method\n```\n\nRun a given test method. Pass one or more fully qualified method names (i.e.,\n'MyNamespace.MyClass.MyTestMethod'). Wildcard '*' is supported at the beginning and/or end\nof each filter.\n    Note: Specifying more than one is an OR operation.\n        This is categorized as a simple filter. You cannot use both simple filters and query filters.\n\n\n### Functional Tests (Playwright)\n\nEnd-to-end tests are located in `test/OrchardCore.Tests.Functional/`.\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n### Automated Browser Testing (Playwright MCP)\n\nFor AI agents, the Playwright MCP (Model Context Protocol) provides automated browser testing capabilities:\n\n- **Setup**: Ensure the application is running at `http://localhost:5000`\n- **Navigation**: Use `mcp_playwright_browser_navigate` to navigate to pages\n- **Interactions**: Use tools like `mcp_playwright_browser_click`, `mcp_playwright_browser_type` for user actions\n- **Verification**: Use `mcp_playwright_browser_snapshot` to capture page state\n- **Console**: Use `mcp_playwright_browser_console_messages` to check for JavaScript errors\n\n**Example workflow:**\n1. Navigate to the application\n2. Complete setup wizard if needed\n3. Navigate to specific features (e.g., `/Admin/Media`)\n4. Interact with UI elements\n5. Verify console has no errors\n6. Capture screenshots or snapshots for validation\n\n### Test Organization\n\n- `test/OrchardCore.Tests/` - Main unit test project\n- `test/OrchardCore.Abstractions.Tests/` - Tests for abstractions\n- `test/OrchardCore.Tests.Functional/` - Playwright E2E functional tests\n- `test/OrchardCore.Tests.Modules/` - Test modules used by tests\n\n## Project Structure\n\n```\nOrchardCore/\n├── src/\n│   ├── OrchardCore/                    # Core framework libraries\n│   │   ├── OrchardCore/                # Main framework\n│   │   ├── OrchardCore.Abstractions/   # Core interfaces\n│   │   └── ...                         # Other abstractions\n│   ├── OrchardCore.Modules/            # Built-in modules\n│   ├── OrchardCore.Themes/             # Built-in themes\n│   ├── OrchardCore.Cms.Web/            # Main CMS web application\n│   └── docs/                           # Documentation source\n├── test/                               # Test projects\n└── .scripts/                           # Build and asset scripts\n```\n\n## Available Skills\n\nThe following skills are available in `.agents/skills/` for guided workflows:\n\n| Skill | Description | Use When |\n|-------|-------------|----------|\n| `orchardcore-module-creator` | Create new modules | Adding modules, content parts, fields, handlers |\n| `orchardcore-theme-creator` | Create new themes | Adding themes, layouts, frontend assets |\n| `orchardcore-recipe-creator` | Create setup recipes | Provisioning a tenant: features, themes, content, roles, settings |\n| `orchardcore-asset-manager` | Build/manage frontend assets | Modifying SCSS, JS, TS, Vue or troubleshooting the asset pipeline |\n| `orchardcore-admin-edit-views` | Build admin edit views | Creating/updating `*.Edit.cshtml` with `ocat-*` classes |\n| `orchardcore-data-migration` | Write data migrations | Altering content definitions, index tables, patching content items |\n| `orchardcore-display-management` | Control rendering | placement.json, drivers, shapes, zones, alternates, editor layouts |\n| `orchardcore-workflow-activity` | Custom workflow activities | New workflow task/event, outcomes, activity editor, input/output |\n| `orchardcore-query-indexing` | Queries & search indexing | SQL/Lucene queries, index profiles, index handlers, search |\n| `orchardcore-localization` | Localize apps & content | IStringLocalizer S/T/H, PO files, content translation, cultures |\n| `orchardcore-tenants` | Multi-tenancy | Shells, creating tenants, tenant scopes, feature profiles, isolation |\n| `orchardcore-unit-test` | Write & run tests | xUnit, SiteContext integration, Moq, Playwright functional |\n| `orchardcore-docs-writer` | Author docs | MkDocs pages, module README, nav, admonitions, redirects |\n| `orchardcore-tester` | Browser-based testing | Testing features via Playwright automation |\n| `orchardcore-nswag-regenerate` | Regenerate NSwag API clients | Updating `Services/OpenApiClient.cs`/`OpenApiClient.ts`, noisy NSwag regeneration diffs |\n\nThese skills provide step-by-step guidance, code templates, and references for common tasks.\n\n## Frontend Assets\n\n### Asset Management\n\nOrchard Core uses an asset manager for compiling SCSS, TypeScript, and JavaScript.\n\n```bash\n# Install Yarn\n\n# Install dependencies (from repository root)\ncorepack enable\nyarn\n\n# Build all assets including gulp\nyarn build\n```\n\n### Assets.json Configuration\n\nEach module with frontend assets needs an `Assets.json` file:\n\n```json\n[\n  {\n    \"action\": \"vite\",\n    \"name\": \"your-module\",\n    \"source\": \"Assets/\",\n    \"tags\": [\"js\", \"css\"]\n  }\n]\n```\n\n### Asset Dependencies (package.json)\n\n```json\n{\n  \"name\": \"@orchardcore/your-module\",\n  \"version\": \"1.0.0\",\n  \"dependencies\": {\n    \"vue\": \"3.5.13\",\n    \"bootstrap\": \"5.3.8\"\n  }\n}\n```\n\n## Content Management Patterns\n\nFor detailed patterns including Content Parts, Content Part Drivers, Content Fields, and more, see the `orchardcore-module-creator` skill in `.agents/skills/`.\n\n## Coding Conventions\n\n### General Guidelines\n\n- Follow [ASP.NET Core Engineering guidelines](https://github.com/dotnet/aspnetcore/wiki/Engineering-guidelines)\n- Use `sealed` for classes that should not be inherited\n- Use file-scoped namespaces\n- Prefer collection expressions (`[]`) over `new List<T>()`\n- Avoid use of primary constructors\n\n### Naming Conventions\n\n- Classes: `PascalCase`\n- Interfaces: `IPascalCase`\n- Methods: `PascalCase`\n- Properties: `PascalCase`\n- Private fields: `_camelCase`\n- Local variables: `camelCase`\n- Constants: `PascalCase`\n\n### Async Conventions\n\n- Suffix async methods with `Async`\n- Use `Task` or `ValueTask` return types\n\n### Code Analysis\n\nThe project uses:\n- StyleCop.Analyzers for style enforcement\n- `AnalysisLevel` set to `latest-Recommended`\n- Specific CA rules are suppressed (see `Directory.Build.props`)\n\n### Documentation\n\n- Update the canonical page under `src\\docs` whenever a change affects user-facing behavior, configuration, setup, public APIs, stereotypes, or extension points.\n- Add or update XML `<summary>` documentation for new or modified public interfaces, domain models, enums, and other public members that are part of the change.\n- Document each enum member individually when its behavior is relevant to users or downstream developers.\n- When XML documentation already exists, revise the existing block in place and keep `<param>` tags accurate and in signature order.\n\n## Database Patterns\n\n### YesSql Usage\n\nOrchard Core uses YesSql as its document database abstraction:\n\n```csharp\npublic class YourService\n{\n    private readonly ISession _session;\n\n    public YourService(ISession session)\n    {\n        _session = session;\n    }\n\n    public async Task<YourDocument> GetAsync(string id)\n    {\n        return await _session.Query<YourDocument, YourIndex>()\n            .Where(x => x.DocumentId == id)\n            .FirstOrDefaultAsync();\n    }\n\n    public async Task SaveAsync(YourDocument document)\n    {\n        await _session.SaveAsync(document);\n    }\n}\n```\n\n### Index Definition\n\n```csharp\npublic class YourIndex : MapIndex\n{\n    public string DocumentId { get; set; }\n    public string Name { get; set; }\n}\n\npublic class YourIndexProvider : IndexProvider<YourDocument>\n{\n    public override void Describe(DescribeContext<YourDocument> context)\n    {\n        context.For<YourIndex>()\n            .Map(doc => new YourIndex\n            {\n                DocumentId = doc.Id,\n                Name = doc.Name,\n            });\n    }\n}\n```\n\n## Testing Patterns\n\n### Unit Test Structure\n\nName test methods with the `{Action}_{Condition}_{ExpectedResult}` format, for example `Write_WithinLimit_Succeeds`.\n\n```csharp\nusing Xunit;\n\nnamespace OrchardCore.Tests.Modules.OrchardCore.YourModule;\n\npublic class YourServiceTests\n{\n    [Fact]\n    public async Task YourMethod_Condition_DoesSomething()\n    {\n        // Arrange\n        var service = new YourService();\n\n        // Act\n        var result = await service.YourMethodAsync();\n\n        // Assert\n        Assert.NotNull(result);\n    }\n\n    [Theory]\n    [InlineData(\"input1\", \"expected1\")]\n    [InlineData(\"input2\", \"expected2\")]\n    public void YourMethod_Input_ReturnsExpected(string input, string expected)\n    {\n        // Test implementation\n    }\n}\n```\n\n### Integration Test with Host\n\n```csharp\npublic class YourIntegrationTests : IClassFixture<OrchardTestFixture>\n{\n    private readonly OrchardTestFixture _fixture;\n\n    public YourIntegrationTests(OrchardTestFixture fixture)\n    {\n        _fixture = fixture;\n    }\n\n    [Fact]\n    public async Task Feature_DefaultRecipe_Works()\n    {\n        // Use _fixture to create test scenarios\n    }\n}\n```\n\n### Manual Testing\n\nFor browser-based manual testing using Playwright, see the `orchardcore-tester` skill in `.agents/skills/`.\n\n**Quick start:**\n```powershell\n# Build\ndotnet build src/OrchardCore.Cms.Web -c Debug -f net10.0\n\n# Generate/get port and start in background\n$port = if (Test-Path .orchardcore-port) { Get-Content .orchardcore-port } else { $p = Get-Random -Min 5000 -Max 6000; $p | Out-File .orchardcore-port -NoNewline; $p }\n$proc = Start-Process dotnet -ArgumentList \"run\",\"-f\",\"net10.0\",\"--no-build\",\"--urls\",\"http://localhost:$port\" -WorkingDirectory \"src/OrchardCore.Cms.Web\" -PassThru -NoNewWindow\n$proc.Id | Out-File .orchardcore-pid -NoNewline\n\n# URL: http://localhost:$port\n# Test credentials: admin / admin@test.com / Password1!\n\n# Stop when done\nStop-Process -Id (Get-Content .orchardcore-pid) -Force; Remove-Item .orchardcore-pid\n\n# Reset state: Remove-Item -Recurse -Force src/OrchardCore.Cms.Web/App_Data\n```\n\n**Debugging**: Check `src/OrchardCore.Cms.Web/App_Data/logs/orchard-log-{date}.log`\n\n### Functional Testing with Playwright\n\nCreate new functional tests under `test/OrchardCore.Tests.Functional/Tests/` following the existing C# test class patterns.\n\nRun the Playwright functional tests:\n\n```bash\n# Run CMS functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Cms*\"\n\n# Run MVC functional tests\ndotnet test test/OrchardCore.Tests.Functional/OrchardCore.Tests.Functional.csproj --filter-class \"*Mvc*\"\n```\n\n## Common Extension Points\n\n### Registering Services\n\n```csharp\n// In Startup.cs\nservices.AddScoped<IYourService, YourService>();\nservices.AddSingleton<IYourSingleton, YourSingleton>();\nservices.AddTransient<IYourTransient, YourTransient>();\n```\n\n### Event Handlers\n\n```csharp\npublic class YourContentHandler : ContentHandlerBase\n{\n    public override Task PublishedAsync(PublishContentContext context)\n    {\n        // Handle content published event\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Background Tasks\n\n```csharp\npublic class YourBackgroundTask : IBackgroundTask\n{\n    public Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)\n    {\n        // Background work implementation\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Navigation/Admin Menu\n\n```csharp\npublic sealed class AdminMenu : AdminNavigationProvider\n{\n    private readonly IStringLocalizer S;\n\n    public AdminMenu(IStringLocalizer<AdminMenu> localizer)\n    {\n        S = localizer;\n    }\n\n    protected override ValueTask BuildAsync(NavigationBuilder builder)\n    {\n        builder\n            .Add(S[\"Your Menu\"], menu => menu\n                .Add(S[\"Your Item\"], S[\"Your Item\"], item => item\n                    .Action(\"Index\", \"Admin\", \"OrchardCore.YourModule\")\n                    .Permission(YourPermissions.ManageYourFeature)\n                    .LocalNav()\n                )\n            );\n\n        return ValueTask.CompletedTask;\n    }\n}\n```\n\n## Debugging Tips\n\n1. **Enable detailed errors** in development by setting `ASPNETCORE_ENVIRONMENT=Development`\n2. **Check tenant logs** in `App_Data/Sites/{TenantName}/logs/`\n3. **Use MiniProfiler** module for performance analysis\n4. **Enable SQL logging** by configuring YesSql logging\n\n## Pull Request Guidelines\n\n1. Follow existing code style and conventions\n2. Include unit tests for new functionality\n3. Update the canonical documentation page when adding or changing user-facing features, public APIs, configuration, stereotypes, or extension points, and keep the docs aligned with the shipped code and behavior\n4. Run asset build if modifying CSS/JS: `yarn build`\n5. Ensure all tests pass: `dotnet test`\n6. Link related GitHub issues using `Fixes #IssueId`\n7. Add release notes for significant changes in `src/docs/releases/`, but do not rely on release notes as the only documentation for a feature; release notes describe what changed, while the canonical docs describe the current behavior without transitional or versioned wording\n\n## Useful Commands\n\n```bash\n# Restore packages\ndotnet restore\n\n# Clean build artifacts\ndotnet clean\n\n# Run\ndotnet run --project src/OrchardCore.Cms.Web\n\n# Build assets\nyarn build\n\n# Lint JavaScript/TypeScript\nyarn lint\n\n# Type check Vue/TypeScript\nyarn check\n```\n\n## Resources\n\n- [Documentation](https://docs.orchardcore.net/)\n- [Contributing Guide](https://docs.orchardcore.net/en/latest/contributing/)\n- [Discord Community](https://orchardcore.net/discord)\n- [Issue Tracker](https://github.com/OrchardCMS/OrchardCore/issues)\n- [API Reference](https://docs.orchardcore.net/en/latest/reference/)\n\n## Admin Edit View Conventions\n\nWhen creating or updating Orchard Core admin edit views, always use the `ocat-*` admin theme classes so the UI stays consistent across the site and works with custom admin theme overrides.\n\nThis applies to admin-facing Razor edit views such as:\n\n- `*.Edit.cshtml`\n- `*.Fields.Edit.cshtml`\n- Admin editor templates rendered in the admin theme\n\n### Required patterns\n\n| Scenario | Required structure |\n|---|---|\n| Standard admin field row (default for all inputs) | `ocat-wrapper` + `ocat-label` + `ocat-end` |\n| Required field label | `ocat-label ocat-label-required` |\n| Checkbox or toggle with no left-column label | `ocat-wrapper` + `ocat-end-offset` |\n| Standalone alert, notice, or section headline inside an edit form | `ocat-wrapper` + `ocat-end-offset` |\n| Limited-width row **only** for `type=\"number\"` inputs or when the user explicitly requests compact width | `ocat-limited-wrapper` + `ocat-label` + `ocat-limited` |\n\n> **Default rule:** Always use the standard `ocat-wrapper` + `ocat-label` + `ocat-end` pattern unless the input is a `type=\"number\"` field or the user explicitly asks for limited/compact width.\n\n### Standard field example\n\n```cshtml\n<div class=\"ocat-wrapper\" asp-validation-class-for=\"DisplayText\">\n    <label asp-for=\"DisplayText\" class=\"ocat-label\">@T[\"Display text\"]</label>\n    <div class=\"ocat-end\">\n        <input asp-for=\"DisplayText\" class=\"form-control\" />\n        <span asp-validation-for=\"DisplayText\"></span>\n        <span class=\"hint\">@T[\"Shown to editors in the admin UI.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field example (number inputs)\n\n```cshtml\n<div class=\"ocat-limited-wrapper\" asp-validation-class-for=\"PageSize\">\n    <label asp-for=\"PageSize\" class=\"ocat-label\">@T[\"Page size\"]</label>\n    <div class=\"ocat-limited\">\n        <input asp-for=\"PageSize\" type=\"number\" class=\"form-control\" />\n        <span asp-validation-for=\"PageSize\"></span>\n        <span class=\"hint\">@T[\"The default page size.\"]</span>\n    </div>\n</div>\n```\n\n### Limited-width field inside a content field or content part wrapper\n\nIf the row also needs Orchard-specific wrapper classes such as `field-wrapper-*` or `content-part-wrapper-*`, keep the outer `ocat-wrapper` and place the compact control inside `ocat-end`:\n\n```cshtml\n<div class=\"ocat-wrapper field-wrapper @($\"field-wrapper-{Model.PartFieldDefinition.PartDefinition.Name.HtmlClassify()}-{Model.PartFieldDefinition.Name.HtmlClassify()}\")\">\n    <label asp-for=\"Value\" class=\"ocat-label\">@T[\"Value\"]</label>\n    <div class=\"ocat-end\">\n        <div class=\"ocat-limited-wrapper\">\n            <div class=\"ocat-limited\">\n                <input asp-for=\"Value\" class=\"form-control\" />\n                <span asp-validation-for=\"Value\"></span>\n            </div>\n        </div>\n        <span class=\"hint\">@T[\"Keeps a compact editor width without losing the field wrapper row.\"]</span>\n    </div>\n</div>\n```\n\n### Standalone alert or headline row\n\nUse `ocat-end-offset` for alerts, notices, legends, and headings that belong to the form but do not have a left-column label:\n\n```cshtml\n<div class=\"ocat-wrapper\">\n    <div class=\"ocat-end-offset\">\n        <h5>@T[\"Section heading\"]</h5>\n        <div class=\"alert alert-warning\" role=\"alert\">\n            @T[\"Important guidance for this form section.\"]\n        </div>\n    </div>\n</div>\n```\n\n### Avoid\n\n- `mb-3`, `form-group`, or `form-label` as the row layout pattern\n- Legacy helper methods such as `@Orchard.GetWrapperClasses()` or `@Orchard.GetLimitedWidthWrapperClasses()`\n- Using `ocat-limited-wrapper` for text inputs, selects, paths, IDs, or other non-number fields unless the user explicitly requests compact width\n- Mixing `ocat-end` and `ocat-end-offset` in the same row; choose exactly one based on whether the row has a left-column label\n","category":"root","tokens":4961}]}