|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) and other coding agents when |
| 4 | +working with code in this repository. `CLAUDE.md` is a symlink to this file, so both names |
| 5 | +resolve to the same guidance. |
| 6 | + |
| 7 | +## Build and Test Commands |
| 8 | + |
| 9 | +### Building the Solution |
| 10 | +```bash |
| 11 | +# Standard build |
| 12 | +dotnet build |
| 13 | +dotnet build -c Release |
| 14 | + |
| 15 | +# Build with warnings as errors (CI validation) |
| 16 | +dotnet build -warnaserror |
| 17 | +``` |
| 18 | + |
| 19 | +### Running Tests |
| 20 | +```bash |
| 21 | +# Run all tests |
| 22 | +dotnet test -c Release |
| 23 | + |
| 24 | +# Run tests for specific framework |
| 25 | +dotnet test -c Release --framework net8.0 |
| 26 | +dotnet test -c Release --framework net48 |
| 27 | + |
| 28 | +# Run specific test by name |
| 29 | +dotnet test -c Release --filter DisplayName="TestName" |
| 30 | + |
| 31 | +# Run tests in a specific project |
| 32 | +dotnet test path/to/project.csproj -c Release |
| 33 | +``` |
| 34 | + |
| 35 | +### Incremental Testing (for changed code only) |
| 36 | +```bash |
| 37 | +# Run only unit tests for changed projects |
| 38 | +dotnet incrementalist run --config .incrementalist/testsOnly.json -- test -c Release --no-build --framework net8.0 |
| 39 | + |
| 40 | +# Run only multi-node tests for changed projects |
| 41 | +dotnet incrementalist run --config .incrementalist/mutliNodeOnly.json -- test -c Release --no-build --framework net8.0 |
| 42 | +``` |
| 43 | + |
| 44 | +### Code Quality |
| 45 | +```bash |
| 46 | +# Format check |
| 47 | +dotnet format --verify-no-changes |
| 48 | + |
| 49 | +# API compatibility check |
| 50 | +dotnet test -c Release src/core/Akka.API.Tests |
| 51 | +``` |
| 52 | + |
| 53 | +### Documentation |
| 54 | +```bash |
| 55 | +# Generate API documentation |
| 56 | +dotnet docfx metadata ./docs/docfx.json --warningsAsErrors |
| 57 | +dotnet docfx build ./docs/docfx.json --warningsAsErrors |
| 58 | +``` |
| 59 | + |
| 60 | +### API Approvals |
| 61 | +- Run API approval tests when making public API changes: `dotnet test -c Release src/core/Akka.API.Tests` |
| 62 | +- Approval files live at `src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt` (and sibling `*.approved.txt` files) |
| 63 | +- A diff viewer (WinMerge, TortoiseMerge, etc.) makes reviewing/approving API changes easier |
| 64 | +- Follow **extend-only** design — don't modify existing public APIs, only extend them |
| 65 | +- Mark deprecated APIs with `[Obsolete("Obsolete since v{current-akka-version}")]` |
| 66 | + |
| 67 | +## High-Level Architecture |
| 68 | + |
| 69 | +### Project Structure |
| 70 | +- **`/src/core/`** - Core actor framework components |
| 71 | + - `Akka/` - Base actor system, routing, dispatchers, configuration |
| 72 | + - `Akka.Remote/` - Distributed actor communication and serialization |
| 73 | + - `Akka.Cluster/` - Clustering, gossip protocols, distributed coordination |
| 74 | + - `Akka.Persistence/` - Event sourcing, snapshots, journals |
| 75 | + - `Akka.Streams/` - Reactive streams with backpressure |
| 76 | + - `Akka.TestKit/` - Testing utilities for actor systems |
| 77 | +- **`/src/contrib/`** - Contributed modules (DI integrations, serializers, cluster extensions) |
| 78 | +- **`/src/benchmark/`** - Performance benchmarks using BenchmarkDotNet |
| 79 | +- **`/src/examples/`** - Sample applications demonstrating patterns |
| 80 | +- **`/src/**/*.Tests/`** - xUnit test projects |
| 81 | +- **`/docs/`** - Public-facing documentation; contributor policies and style guides live under `docs/community/contributing/` |
| 82 | + |
| 83 | +### Key Architectural Concepts |
| 84 | +- **Actor Model**: Message-driven, hierarchical supervision, location transparency |
| 85 | +- **Fault Tolerance**: Supervision strategies, let-it-crash philosophy |
| 86 | +- **Distribution**: Remote actors, clustering, sharding |
| 87 | +- **Reactive Streams**: Backpressure-aware stream processing |
| 88 | +- **Event Sourcing**: Persistence with journals and snapshots |
| 89 | + |
| 90 | +## Code Style and Conventions |
| 91 | + |
| 92 | +### C# Style |
| 93 | +- Allman style braces (opening brace on new line) |
| 94 | +- 4 spaces indentation, no tabs |
| 95 | +- Private fields prefixed with underscore `_fieldName`; PascalCase for public/protected members |
| 96 | +- Use `var` when the type is apparent |
| 97 | +- No `this.` qualifier unless necessary |
| 98 | +- Sort `using` statements with `System.*` first |
| 99 | +- XML doc comments on public APIs |
| 100 | +- Default to `sealed` classes and records |
| 101 | +- Enable `#nullable enable` in new/modified files |
| 102 | +- Never use `async void`, `.Result`, or `.Wait()` — these cause deadlocks |
| 103 | +- Always pass `CancellationToken` through async call chains |
| 104 | + |
| 105 | +### API Design |
| 106 | +- Maintain compatibility with JVM Akka while being .NET idiomatic |
| 107 | +- Use `Task<T>` instead of Future, `TimeSpan` instead of Duration |
| 108 | +- Extend-only design - don't modify existing public APIs |
| 109 | +- Preserve wire format compatibility for serialization |
| 110 | +- Include unit tests with all changes |
| 111 | + |
| 112 | +### Test Naming |
| 113 | +- Use `DisplayName` attribute for descriptive test names |
| 114 | +- Follow pattern: `Should_ExpectedBehavior_When_Condition` |
| 115 | + |
| 116 | +### General Conventions |
| 117 | +- Keep pull requests small and focused (< 300 lines when possible) |
| 118 | +- Fix warnings instead of suppressing them |
| 119 | +- Treat `TBD` comments as action items to be resolved |
| 120 | +- Benchmark performance-critical changes with BenchmarkDotNet |
| 121 | +- Avoid adding new dependencies without a license/security check |
| 122 | + |
| 123 | +## Akka.NET TestKit Guidelines |
| 124 | +- Actor tests should derive from `AkkaSpec` or `TestKit` to access actor-testing facilities |
| 125 | +- **Always use async TestKit methods** (e.g. `ExpectMsgAsync`, `ExpectNoMsgAsync`, `AwaitAssertAsync`, `FishForMessageAsync`, `ResolveOne`) — never the synchronous variants (`ExpectMsg`, `ExpectNoMsg`, `AwaitAssert`, `.Result`, `.Wait()`) |
| 126 | +- Pass `ITestOutputHelper output` to the test constructor and forward it to the base: `public MySpec(ITestOutputHelper output) : base(config, output)` — this captures all test output, including actor-system logs |
| 127 | +- Configure logging in tests as needed: `akka.loglevel = DEBUG` or `akka.loglevel = INFO` |
| 128 | +- Use `EventFilter` to assert on log messages (e.g. `await EventFilter.Error().ExpectOneAsync(async () => { /* test code */ })`) |
| 129 | +- For dead letters, use `EventFilter.DeadLetter()` (e.g. `await EventFilter.DeadLetter().ExpectAsync(1, async () => { /* code that should dead-letter */ })`) |
| 130 | +- Use `TestProbe` for lightweight test actors to verify interactions |
| 131 | +- Set explicit timeouts on message expectations to avoid long-running tests |
| 132 | +- Tests should clean up after themselves (stop created actors, reset state) |
| 133 | +- Multi-node tests live in separate `*.Tests.MultiNode.csproj` projects |
| 134 | +- To verify specialized message wrappers, check the log form `wrapped in [$TypeName]` |
| 135 | + |
| 136 | +## Development Workflow |
| 137 | + |
| 138 | +### Git Branches |
| 139 | +- **`dev`** - Main development branch (default for PRs) |
| 140 | +- **`v1.4`**, **`v1.3`**, etc. - Version maintenance branches for older releases |
| 141 | +- Feature branches: `feature/description` |
| 142 | +- Bugfix branches: `fix/description` |
| 143 | + |
| 144 | +### Git Repository Management |
| 145 | +- Remotes: |
| 146 | + - `akkadotnet` / `upstream` → `https://github.com/akkadotnet/akka.net.git` (main repository) |
| 147 | + - `origin` → your fork (e.g. `https://github.com/yourusername/akka.net.git`) |
| 148 | +- Sync with upstream: |
| 149 | + - `git fetch akkadotnet` (or `upstream`) |
| 150 | + - `git checkout dev` |
| 151 | + - `git merge akkadotnet/dev` |
| 152 | +- Create a feature branch: |
| 153 | + - `git checkout -b feature/your-feature-name` |
| 154 | + - `git push -u origin feature/your-feature-name` |
| 155 | + |
| 156 | +### Making Changes |
| 157 | +1. Always read existing code patterns in the module you're modifying |
| 158 | +2. Follow existing conventions for that specific module |
| 159 | +3. Add/update tests for your changes |
| 160 | +4. Run incremental tests before committing |
| 161 | +5. Ensure API compatibility tests pass for core changes |
| 162 | +6. If the change is breaking, record it in `BREAKING_CHANGES_V1.6.md` in the same change (see below) |
| 163 | + |
| 164 | +### Tracking Breaking Changes (v1.6 cycle) |
| 165 | +Until a stable **v1.6.0** ships, **every** change that goes into the `dev` branch and |
| 166 | +introduces a **breaking behavior, wire-format, or public-API change** MUST be documented in |
| 167 | +[`BREAKING_CHANGES_V1.6.md`](BREAKING_CHANGES_V1.6.md) (repo root), in the **same PR** that |
| 168 | +makes the change. Use the entry format described in that file (status, component, type, |
| 169 | +change, migration). This ledger is retired once `v1.6.0` is released, when its contents are |
| 170 | +folded into the release notes / upgrade guide. |
| 171 | + |
| 172 | +### Target Frameworks |
| 173 | +- **.NET 8.0** - Primary target |
| 174 | +- **.NET 6.0** - Library compatibility |
| 175 | +- **.NET Framework 4.8** - Legacy support |
| 176 | +- **.NET Standard 2.0** - Library compatibility |
| 177 | + |
| 178 | +## Important Files |
| 179 | +- `Directory.Build.props` - MSBuild properties, package versions |
| 180 | +- `global.json` - .NET SDK version (8.0.403) |
| 181 | +- `xunit.runner.json` - Test configuration (60s timeout, no parallelization) |
| 182 | +- `.incrementalist/*.json` - Incremental build configurations |
| 183 | +- `RELEASE_NOTES.md` - Version history and changelog |
| 184 | +- `BREAKING_CHANGES_V1.6.md` - Running list of v1.6 breaking changes (until v1.6.0 ships) |
0 commit comments