From automation
Applies Sun Lab C# coding conventions when writing, reviewing, or refactoring code. Covers .cs files, XML documentation, naming, formatting, error handling, using directives, file ordering, and Unity-specific patterns. Use when writing new C# code, modifying existing code, reviewing pull requests, or when the user asks about C# coding standards.
npx claudepluginhub sun-lab-nbb/ataraxis --plugin automationThis skill uses the workspace's default tool permissions.
Applies Sun Lab C# coding conventions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Applies Sun Lab C# coding conventions.
You MUST read this skill and load the relevant reference files before writing or modifying C# code. You MUST verify your changes against the checklist before submitting.
Covers:
Does not cover:
/readme-style)/commit)/skill-design)/explore-codebase)You MUST follow these steps when this skill is invoked.
Read this entire file. The core conventions below apply to ALL C# code.
Based on the task, load the appropriate reference files:
| Task | Reference to load |
|---|---|
| Writing or modifying XML docs / type usage | xml-docs-and-types.md |
| Writing classes, enums, or Unity components | class-patterns.md |
| Using LINQ, async, IDisposable, or testing | libraries-and-tools.md |
| Deploying or verifying tool config files | assets/ directory |
| Reviewing code before submission | anti-patterns.md |
Load multiple references when the task spans multiple domains.
Write or modify C# code following all conventions from this file and the loaded references.
Complete the verification checklist at the end of this file. Every item must pass before submitting work. For anti-pattern examples, load anti-patterns.md.
Sun Lab projects span Python, C++, and C#. These conventions maximize visual and structural consistency across languages while respecting each language's idiomatic standards.
Shared across all languages:
_camelCase)C#-specific divergences from C++:
kPrefix as in C++)kPrefix as in C++)#region blocks are NOT used (prefer blank lines between logical groups)Use full words, not abbreviations:
| Avoid | Prefer |
|---|---|
pos, idx | position, index |
msg, val | message, value |
seg, trig | segment, trigger |
cfg, cnt | configuration, count |
| Element | Convention | Example |
|---|---|---|
| Classes | PascalCase | StimulusTriggerZone, TaskTemplate |
| Methods | PascalCase | ResetState, GetSegmentLengths |
| Public fields | camelCase | trackLength, requireLick, isActive |
| Public properties | PascalCase | IsOccupancyMode, CorridorSpacingUnity |
| Private fields | _camelCase | _currentSegmentIndex, _occupancyTimer |
| Local variables | camelCase | segmentPath, measuredLength |
| Parameters | camelCase | configPath, qosLevel |
| Constants | PascalCase | LengthComparisonEpsilon |
| Enum types | PascalCase | ControllerTypes, StimulusMode |
| Enum values | PascalCase | LinearTreadmill, OccupancyBased |
| Namespaces | PascalCase | Gimbl, SL.Config |
| Interfaces | IPascalCase | IConfigurable, IResettable |
| Type parameters | TPascalCase | TMessage, TConfig |
In Unity projects, MonoBehaviour and ScriptableObject classes expose public fields using camelCase for Inspector serialization. These are effectively configuration parameters set via the Unity Editor:
/// <summary>Determines whether the task requires a lick to start a trial.</summary>
public bool requireLick = false;
/// <summary>The length of the track in Unity units.</summary>
public float trackLength = 10f;
Use PascalCase properties for computed values or encapsulated access:
/// <summary>Determines whether this zone uses occupancy-based stimulus triggering.</summary>
public bool IsOccupancyMode => _occupancyZone != null;
CreateNewTask, ValidateTemplate, ResetStateProcess, Handle, DoSomethingUse PascalCase for const and static readonly fields. Prefer immutability by default:
const: Compile-time constants (primitives, strings). Inlined at call sites.static readonly: Runtime-initialized immutable values (objects, computed values).readonly: Instance fields assigned only in constructors or field initializers./// <summary>The tolerance for comparing measured prefab lengths against configured lengths.</summary>
private const float LengthComparisonEpsilon = 0.01f;
/// <summary>The default configuration path resolved at runtime.</summary>
private static readonly string DefaultConfigPath = Path.Combine(Application.dataPath, "config");
/// <summary>The communication port assigned at construction time.</summary>
private readonly SerialPort _port;
You MUST mark fields as readonly when they are only assigned in the constructor or initializer.
For detailed immutability patterns (readonly struct, records, in parameters), see
class-patterns.md.
Prefer named arguments when the meaning is not obvious from the value alone:
// Good - named arguments clarify boolean and same-type parameters
CreateChannel(topic: "sensors/encoder", isListener: true, qosLevel: 2);
Instantiate(prefab: segmentPrefab, position: spawnPosition, rotation: Quaternion.identity);
// Acceptable - single argument or meaning obvious from type/name
Mathf.Abs(difference);
Debug.Log(message);
GetComponent<MeshRenderer>();
Use named arguments when a method has:
Use Unity's logging system for error reporting:
if (template == null)
{
Debug.LogError("Failed to load task template from YAML file.");
return;
}
if (Mathf.Abs(measuredLength - configuredLength) > LengthComparisonEpsilon)
{
Debug.LogWarning(
$"For {segmentName}, mismatch between prefab length ({measuredLength}) "
+ $"and configured length ({configuredLength})."
);
}
Use a structured format: context ("Unable to..."), constraint ("must be..."), actual value
("but [actual state]."). Use Debug.LogError() for failures that prevent continuation,
Debug.LogWarning() for non-critical issues, and Debug.Log() for informational messages.
if (template == null)string.IsNullOrEmpty() for string validationTryGetComponent<T>() for safe component access in Unity?.) for optional chains??) for default values// Measures actual prefab lengths and compares with configuration.
float[] measuredSegmentLengths = Utility.GetSegmentLengths(segmentPrefabs);
// Set x to 5 before x = 5)// ====== or // ------)#region / #endregion blocks (use blank lines between logical groups instead)this. qualifier (exception: disambiguating a parameter from a field)using directives must be at the top of the file, outside the namespacedotnet_sort_system_directives_first = true)using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Gimbl;
using SL.Config;
All definitions within a file follow this vertical ordering from top to bottom:
/// <summary> block describing the file)namespace SL.Config;)const and static readonly fields)
b. Public fields (Unity Inspector-serialized)
c. Private fields (_camelCase)
d. Properties
e. Unity lifecycle methods (Awake, Start, Update, OnDestroy)
f. Public methods
g. Private methods
h. Nested classesWithin each member kind, order by visibility: public -> internal -> protected ->
private. Always write access modifiers explicitly — never rely on C#'s implicit private
default. Unity lifecycle methods appear in their natural execution order regardless of
visibility.
Each .cs file should contain exactly one public type. The file name must match the class
name (e.g., OccupancyZone.cs contains class OccupancyZone). Nested helper classes and
message types may remain in the containing class's file.
Prefer early returns (guard clauses) over deeply nested conditionals. Use explicit boolean
checks, string.IsNullOrEmpty() for strings, and == null / != null for null checks:
/// <summary>Checks if the occupancy duration has been met while the animal is in the zone.</summary>
void Update()
{
if (!isActive || boundaryDisarmed)
return;
if (string.IsNullOrEmpty(_zoneName))
return;
if (_occupancyTimer.IsRunning && inZone)
{
if (_occupancyTimer.ElapsedMilliseconds >= occupancyDurationMs)
{
OnOccupancyMet();
}
}
}
.csharpierrc.yaml).editorconfig)$"...") for all string formatting@"...") for paths and multi-line stringsC# does not enforce trailing commas in the same way as Python. Follow CSharpier's output for comma placement in multi-line constructs.
Always use braces for control flow statements, even single-line bodies:
// Good
if (template == null)
{
return;
}
// Acceptable for simple guard clauses
if (!isActive)
return;
CSharpier is the primary formatter. Install and use it before committing:
dotnet tool install -g csharpier # Install globally
csharpier . # Format all files
csharpier --check . # Check without modifying (CI mode)
Configuration lives in .csharpierrc.yaml:
printWidth: 120
useTabs: false
tabWidth: 4
endOfLine: lf
The .editorconfig file enforces naming conventions, brace style, and spacing rules in
IDEs. It is the source of truth for style rules that CSharpier does not cover (naming,
var preferences, expression-bodied members).
The .csharpierignore file excludes Unity-generated directories (Library/, Temp/,
Logs/) and third-party packages from formatting.
Canonical configs are stored in assets/. When working in a C# project, verify that
.csharpierrc.yaml, .editorconfig, and .csharpierignore in the project root match these:
The .csharpierignore contains generic entries only. Individual projects may need additional
project-specific entries (e.g., paths to auto-generated scripts).
| Skill | Relationship |
|---|---|
/python-style | Provides Python conventions; C# conventions parallel these |
/cpp-style | Provides C++ conventions; C# conventions parallel these |
/project-layout | Provides C# Unity directory tree; invoke for project structure |
/readme-style | Provides README conventions; invoke for README tasks |
/commit | Provides commit message conventions; invoke for commit tasks |
/skill-design | Provides skill file conventions; invoke for skill authoring tasks |
/explore-codebase | Provides project context that informs style-compliant code changes |
When reviewing or modifying C# code, proactively check for style violations and fix them. When writing new code, apply all conventions from this skill and its references without being asked. If you notice existing code near your changes that violates conventions, mention it to the user but do not fix it unless asked.
You MUST verify your edits against this checklist before submitting any changes to C# files.
C# Style Compliance:
- [ ] XML documentation on all public and private members
- [ ] Summary tags use third-person imperative mood ("Provides..." not "This class provides...")
- [ ] Boolean members documented with "Determines whether..."
- [ ] File-level XML summary comment present
- [ ] All lines ≤ 120 characters
- [ ] 4-space indentation, no tabs
- [ ] Allman brace style (opening braces on new lines)
- [ ] LF line endings
- [ ] Full words used (no abbreviations like pos, idx, val, msg)
- [ ] Private fields use _camelCase prefix
- [ ] Public fields use camelCase (Unity serialized fields)
- [ ] Public properties use PascalCase
- [ ] Constants use PascalCase (const and static readonly)
- [ ] Methods use PascalCase (both public and private)
- [ ] Enum types and values use PascalCase
- [ ] Access modifiers always explicit (never rely on implicit private)
- [ ] Using directives at top of file, outside namespace
- [ ] System directives sorted first
- [ ] String interpolation used (not string.Format or concatenation)
- [ ] Named arguments used for boolean params and ambiguous calls
- [ ] Null checks use explicit comparison (== null, != null)
- [ ] Guard clauses / early returns preferred over deep nesting
- [ ] Fields marked readonly when only assigned in constructor/initializer
- [ ] No #region blocks; no this. qualifier (except disambiguation)
- [ ] One public type per file; file name matches class name
- [ ] Unity logging uses Debug.LogError/LogWarning/Log appropriately
- [ ] CSharpier formatting applied before commit
- [ ] Inline comments use third person imperative
Unity-Specific Compliance:
- [ ] MonoBehaviour fields for Inspector use public camelCase
- [ ] Private backing fields use [SerializeField] when Inspector access needed
- [ ] Lifecycle methods in execution order (Awake, Start, Update, OnDestroy)
- [ ] TryGetComponent used for safe component access
- [ ] No unnecessary GetComponent calls in Update loops
- [ ] No LINQ in Update/FixedUpdate (allocations in hot paths)
- [ ] IDisposable resources cleaned up in OnDestroy