📘 This document is the single source of truth for all contributors (humans and AI agents) to Terminal.Gui.
Welcome! This guide provides everything you need to know to contribute effectively to Terminal.Gui, including project structure, build instructions, coding conventions, testing requirements, and CI/CD workflows.
Terminal.Gui is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It's a large codebase (~1,050 C# files) providing a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system.
Key characteristics:
global.json).editorconfig and Terminal.sln.DotSettings)ALWAYS run these commands from the repository root:
Restore packages (required first, ~15-20 seconds):
dotnet restore
Build solution (Debug, ~50 seconds):
dotnet build --configuration Debug --no-restore
Build Release (for packaging):
dotnet build --configuration Release --no-restore
Two test projects exist:
Non-parallel tests (depend on static state, ~10 min timeout):
dotnet test Tests/UnitTests --no-build --verbosity normal
Application.Init and static state--blame flags for crash diagnosticsParallel tests (can run concurrently, ~10 min timeout):
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
Integration tests:
dotnet test Tests/IntegrationTests --no-build --verbosity normal
Solution: Restore these projects explicitly:
dotnet restore ./Examples/NativeAot/NativeAot.csproj -f
dotnet restore ./Examples/SelfContained/SelfContained.csproj -f
UICatalog (comprehensive demo app):
dotnet run --project Examples/UICatalog/UICatalog.csproj
⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:
.editorconfig and Terminal.sln.DotSettingsCtrl-E-C)Ctrl-K-D) as fallback.editorconfig settings (e.g., braces on new lines, spaces after keywords)ALWAYS use explicit types - Never use var except for built-in simple types (int, string, bool, double, float, decimal, char, byte)
// ✅ CORRECT - Explicit types
View view = new () { Width = 10 };
MouseEventArgs args = new () { Position = new Point(5, 5) };
List<View?> views = new ();
var count = 0; // OK - int is a built-in type
var name = "test"; // OK - string is a built-in type
// ❌ WRONG - Using var for non-built-in types
var view = new View { Width = 10 };
var args = new MouseEventArgs { Position = new Point(5, 5) };
var views = new List<View?>();
ALWAYS use target-typed new () - Use new () instead of new TypeName() when the type is already declared
// ✅ CORRECT - Target-typed new
View view = new () { Width = 10 };
MouseEventArgs args = new ();
// ❌ WRONG - Redundant type name
View view = new View() { Width = 10 };
MouseEventArgs args = new MouseEventArgs();
⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, and samples.
TestResults/ directory at repository rootUnitTestsParallelizable when possibleApplication.Init, ConfigurationManager in tests[AutoInitShutdown] - Legacy pattern, being phased outxunit.runner.json - xUnit configurationcoverlet.runsettings - Coverage settings (OpenCover format)All public APIs MUST have XML documentation:
<summary> tags<see cref=""/> for cross-references<remarks> for context<example> for non-obvious usagedocfx/docs/*.md filesDescription:
copilot pointing to your forkExample:
# To pull down this PR locally:
git remote add copilot <your-fork-url>
git fetch copilot <branch-name>
git checkout copilot/<branch-name>
Coding Style: Follow all coding conventions in this document for new and modified code
Tests: Add tests for new functionality (see Testing Requirements)
Coverage: Maintain or increase code coverage
Scenarios: Update UICatalog scenarios when adding features
Warnings: CRITICAL - PRs must not introduce any new warnings
[Obsolete] attributes can remainThe repository uses multiple GitHub Actions workflows. What runs and when:
.github/workflows/build.yml)v2_release, v2_develop (ignores **.md); supports workflow_callubuntu-latest, 10 minutesdotnet restoredotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612Examples/NativeAot and Examples/SelfContainedbuild-artifacts, retention 1 day.github/workflows/unit-tests.yml)v2_release, v2_develop (ignores **.md)dotnet restore (required for --no-build to work)Tests/UnitTests with blame/diag flags; xunit.stopOnFail=falseTests/UnitTestsParallelizable with blame/diag flags; xunit.stopOnFail=falseTest results: All tests output to unified TestResults/ directory at repository root
.github/workflows/integration-tests.yml)v2_release, v2_develop (ignores **.md)dotnet restorexunit.stopOnFail=true.github/workflows/publish.yml)v2_release, v2_develop, and tags v*(ignores **.md)NUGET_API_KEY.github/workflows/api-docs.yml)v1_release and v2_developref_name is v2_release or v2_develop# Full CI sequence:
dotnet restore
dotnet build --configuration Debug --no-restore
dotnet test Tests/UnitTests --no-build --verbosity normal
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
dotnet build --configuration Release --no-restore
Terminal.sln - Main solution fileTerminal.sln.DotSettings - ReSharper code style settings.editorconfig - Code formatting rules (111KB, extensive)global.json - .NET SDK version pinningDirectory.Build.props - Common MSBuild propertiesDirectory.Packages.props - Central package version managementGitVersion.yml - Version numbering configurationCONTRIBUTING.md - This file - contribution guidelines (source of truth)AGENTS.md - Pointer to this file for AI agentsREADME.md - Project documentation/Terminal.Gui/ - Core library (496 C# files):
App/ - Application lifecycle (Application.cs static class, SessionToken, MainLoop)Configuration/ - ConfigurationManager for settingsDrivers/ - Console driver implementations (Dotnet, Windows, Unix, Fake)Drawing/ - Rendering system (attributes, colors, glyphs)Input/ - Keyboard and mouse input handlingViewBase/ - Core View class hierarchy and layoutViews/ - Specific View subclasses (Window, Dialog, Button, ListView, etc.)Text/ - Text manipulation and formattingFileServices/ - File operations and services/Tests/:
UnitTests/ - Non-parallel tests (use Application.Init, static state)UnitTestsParallelizable/ - Parallel tests (no static dependencies) - PreferredIntegrationTests/ - Integration testsStressTests/ - Long-running stress tests (scheduled daily)coverlet.runsettings - Code coverage configuration/Examples/:
UICatalog/ - Comprehensive demo app for manual testingExample/ - Basic exampleNativeAot/, SelfContained/ - Deployment examplesReactiveExample/, CommunityToolkitExample/ - Integration examples/docfx/ - Documentation source:
docs/ - Conceptual documentation (deep dives)api/ - Generated API docs (gitignored)docfx.json - DocFX configuration/Scripts/ - PowerShell build utilities (requires PowerShell 7.4+)
/.github/workflows/ - CI/CD pipelines (see CI/CD Workflows)
v2_develop - Default branch, active developmentv2_release - Stable releases, matches NuGetv1_develop, v1_release - Legacy v1 (maintenance only)⚠️ CRITICAL - Contributors should understand these concepts before starting work.
See /docfx/docs/ for deep dives on:
Application.Init, Application.Run, and Application.Shutdown workView, Toplevel, Window, and view containmentKey documentation:
UnitTests if they can be parallelizableApplication.Init in new testsvar for anything but built-in simple types (use explicit types)new (ALWAYS PREFER target-typed new ())[Obsolete] warnings)/docfx/docs/ directoryThank you for contributing to Terminal.Gui! 🎉