agentleFS
sshnetsshnet/SSH.NET/.github/copilot-instructions.md

SSH.NET

Copilot instructions4.4k starsChanged 4 months agoMITView on GitHub

SSH.NET is a .NET library for SSH-2 protocol communication, optimized for parallelism. It provides: Primary entry points are SshClient, SftpClient, ScpClient, and NetConfClient, all extending BaseClient. Large classes are split into partial class files per concern (e.g., PrivateKeyFile.PKCS1.cs, PrivateKeyFile.OpenSSH.cs). StyleCop is enforced. Follow existing file conventions: Use the existing exception hierarchy; do not throw Exception or ApplicationException directly.

We split this copilot-instructions.md into the rules it gives an agent

13 rules. About 0 are common, 3 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    StyleCop is enforced: Follow existing file conventions:

    line 66
  2. Very specific:

    Use the existing exception hierarchy.

    line 79
  3. Very specific:

    Prefer ReadOnlyMemory<byte> / Memory<byte> over byte[] in new protocol-layer code.

    line 106
  4. Very specific:

    Do not expose mutable collections directly.

    line 107
  5. Very specific:

    Use async Task / async ValueTask with CancellationToken for all new async methods.

    line 113
  6. Very specific:

    Prefer TaskCompletionSource<T> to bridge event-driven or callback-based code into the async model.

    line 115
  7. Very specific:

    Never block inside async code with .Result or .Wait() — this can cause deadlocks on synchronization-context-bound callers.

    line 116
  8. Very specific:

    Use ConfigureAwait(false) in library code (this is a class library, not an app).

    line 117
  9. Very specific:

    Run with dotnet test like any other project once Docker is available.

    line 164
  10. Distinctive:

    Add unit tests for every new public method and every non-trivial internal method.

    line 181
  11. Very specific:

    Test both the happy path and error/edge cases (e.g., null arguments, disposed state, cancellation).

    line 182
  12. Distinctive:

    Do not remove or weaken existing tests.

    line 184
  13. Very specific:

    Prefer ArrayPool<byte>.Shared or MemoryPool<byte>.Shared over allocating new byte[] in protocol encoding/decoding.

    line 191

≈ “Common” is an estimate: at least 1 in 5 of the 3,669 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
copilot-instructions.md

GitHub Copilot Instructions for SSH.NET

What this repository does

SSH.NET is a .NET library for SSH-2 protocol communication, optimized for parallelism. It provides:

  • SSH command execution (synchronous and async)
  • SFTP file operations (synchronous and async)
  • SCP file transfers
  • Port forwarding (local, remote, dynamic/SOCKS)
  • Interactive shell via ShellStream
  • NetConf protocol client
  • Multi-factor and certificate-based authentication

Primary entry points are SshClient, SftpClient, ScpClient, and NetConfClient, all extending BaseClient.


Core technologies

AreaTechnology
LanguageC# (LangVersion=latest) with #nullable enable everywhere
Runtimes.NET Framework 4.6.2, .NET Standard 2.0, .NET 8+, .NET 9+, .NET 10+
CryptographyBouncyCastle (BouncyCastle.Cryptography)
LoggingMicrosoft.Extensions.Logging.Abstractions (ILogger/ILoggerFactory)
TestingMSTest v4, Moq, Testcontainers (Docker for integration tests)
Build tooling.NET SDK 10.0.100, Nerdbank.GitVersioning
Static analysisStyleCop.Analyzers, Meziantou.Analyzer, SonarAnalyzer.CSharp

Code organization

src/Renci.SshNet/
├── Channels/          # SSH channel types (session, forwarded, X11…)
├── Common/            # Shared utilities, extension methods, custom exceptions
├── Compression/       # Zlib compression support
├── Connection/        # Socket connectors, proxy support (SOCKS4/5, HTTP), key exchange
├── Messages/          # SSH protocol message types
│   ├── Transport/
│   ├── Authentication/
│   └── Connection/
├── Security/          # Algorithms, key-exchange, cryptography wrappers
│   └── Cryptography/  # Ciphers, signatures, key types
├── Sftp/              # SFTP session, requests, responses
├── Netconf/           # NetConf client
└── Abstractions/      # Platform and I/O abstractions

Large classes are split into partial class files per concern (e.g., PrivateKeyFile.PKCS1.cs, PrivateKeyFile.OpenSSH.cs).


Naming and style conventions

ElementConventionExample
Classes, methods, propertiesPascalCaseSftpClient, ListDirectory(), IsConnected
Private fields_camelCase_isDisposed, _sftpSession
InterfacesI prefix + PascalCaseISftpClient, IChannel
Constants / static readonlyPascalCaseMaximumSshPacketSize
Local variablescamelCaseoperationTimeout, connectionInfo

StyleCop is enforced. Follow existing file conventions:

  • #nullable enable at the top of every .cs file.
  • using directives outside the namespace block, grouped with System.* first, then a blank line, then other namespaces.
  • 4-space indentation (spaces, not tabs).
  • XML doc comments (///) on all public and internal members; use <inheritdoc/> when inheriting from an interface.
  • Describe exception conditions in /// <exception cref="…"> tags.
  • No Hungarian notation.

Error handling

Use the existing exception hierarchy; do not throw Exception or ApplicationException directly.

SshException
├── SshConnectionException       # connection-level failures
├── SshAuthenticationException   # auth failures
├── SshOperationTimeoutException # operation timed out
├── SshPassPhraseNullOrEmptyException
├── ProxyException
├── SftpException
│   ├── SftpPermissionDeniedException
│   └── SftpPathNotFoundException
├── ScpException
└── NetConfServerException
  • Annotate new exception classes with #if NETFRAMEWORK [Serializable] #endif and add the protected serialization constructor inside the same #if block, matching the pattern in SshException.cs.
  • Surface async errors by storing them in a TaskCompletionSource or re-throwing via ExceptionDispatchInfo.Throw() — never swallow exceptions silently.
  • Raise ErrorOccurred events on long-running components (e.g., ForwardedPort, Session) rather than propagating the exception across thread boundaries.

API design

  • Every public blocking method should have a …Async(CancellationToken cancellationToken = default) counterpart. Keep both in the same partial class file or co-located partial file.
  • Validate all arguments at the top of public methods; prefer ArgumentNullException, ArgumentException, ArgumentOutOfRangeException with descriptive messages.
  • Return IEnumerable<T> for sequences that are already materialized; use IAsyncEnumerable<T> when data streams asynchronously.
  • Prefer ReadOnlyMemory<byte> / Memory<byte> over byte[] in new protocol-layer code.
  • Do not expose mutable collections directly; use .AsReadOnly() or copy-on-return.

Async and concurrency

  • Use async Task / async ValueTask with CancellationToken for all new async methods.
  • The socket receive loop and keep-alive timer run on dedicated background threads; protect shared state with lock or the custom internal Lock type used in Session.
  • Prefer TaskCompletionSource<T> to bridge event-driven or callback-based code into the async model.
  • Never block inside async code with .Result or .Wait() — this can cause deadlocks on synchronization-context-bound callers.
  • Use ConfigureAwait(false) in library code (this is a class library, not an app).

Security-sensitive areas

These areas require extra care:

  • src/Renci.SshNet/Security/ — key exchange, algorithm negotiation. Algorithm choices have direct security implications.
  • src/Renci.SshNet/PrivateKeyFile*.cs — key format parsing (PKCS#1, PKCS#8, OpenSSH, PuTTY, ssh.com). Input is untrusted; validate lengths and offsets before indexing.
  • src/Renci.SshNet/Connection/ — host key verification. Never bypass host key checking silently.
  • Sensitive data in memory: clear key material as soon as it is no longer needed; do not log private key bytes or plaintext passwords even at Debug level.
  • SshNetLoggingConfiguration.WiresharkKeyLogFilePath is a Debug-only diagnostic that writes session keys to disk. It must never be enabled in production builds.
  • Cryptographic primitives come from BouncyCastle. Prefer existing wrappers over direct calls to BouncyCastle APIs; adding new algorithms requires corresponding unit tests and algorithm negotiation entries.

Testing

Unit tests (test/Renci.SshNet.Tests/)

  • Framework: MSTest ([TestClass], [TestMethod], [TestInitialize], [TestCleanup])
  • Mocking: Moq — use Mock<T>, .Setup(…), .Verify(…)
  • File naming: {ClassName}Test[_{Scenario}].cs (e.g., SftpClientTest.ConnectAsync.cs)
  • Each scenario lives in its own partial class file inside Classes/
  • Base classes: TestBase, SessionTestBase, BaseClientTestBase — extend the appropriate base
  • Arrange-Act-Assert style; each test method is focused on a single observable behaviour
[TestMethod]
public void MethodName_Scenario_ExpectedOutcome()
{
    // Arrange
    var connectionInfo = new PasswordConnectionInfo("host", 22, "user", "pwd");
    var target = new SftpClient(connectionInfo);

    // Act
    var actual = target.SomeProperty;

    // Assert
    Assert.AreEqual(expected, actual);
}

Integration tests (test/Renci.SshNet.IntegrationTests/)

  • Require Docker (via Testcontainers); a running Docker daemon is a prerequisite.
  • Run with dotnet test like any other project once Docker is available.

Running tests

# Unit tests only
dotnet test test/Renci.SshNet.Tests/

# All tests (requires Docker)
dotnet test

# With code coverage
dotnet test --collect:"XPlat Code Coverage"

What to test

  • Add unit tests for every new public method and every non-trivial internal method.
  • Test both the happy path and error/edge cases (e.g., null arguments, disposed state, cancellation).
  • For async methods, test cancellation via CancellationToken and timeout behaviour.
  • Do not remove or weaken existing tests; add new tests instead.

Performance considerations

  • SSH.NET is designed for parallelism; avoid introducing lock contention on hot paths.
  • Prefer ArrayPool<byte>.Shared or MemoryPool<byte>.Shared over allocating new byte[] in protocol encoding/decoding.
  • The BufferSize on SftpClient controls read/write payload sizes; keep protocol overhead in mind when changing defaults.
  • Benchmark significant changes with test/Renci.SshNet.Benchmarks/ using BenchmarkDotNet.

Making changes safely

  1. Run the unit tests first (dotnet test test/Renci.SshNet.Tests/) to establish a clean baseline.
  2. Keep changes focused. Small, targeted PRs merge faster. Separate refactoring from behaviour changes.
  3. Multi-targeting: the library targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET. Use #if NETFRAMEWORK / #if NET guards for platform-specific code; confirm all TFMs build with dotnet build.
  4. Public API changes: adding new overloads or members is generally safe. Removing or changing existing signatures is a breaking change — discuss in an issue first.
  5. Cryptographic changes: consult existing algorithm registration lists (in ConnectionInfo.cs and Session.cs) before adding or removing algorithms.
  6. StyleCop and analyzers: the build treats analyzer warnings as errors in Release/CI mode. Run dotnet build -c Release locally to catch these before pushing.
  7. CI note: some integration tests can flake due to timing or networking. If an existing (unrelated) test fails intermittently in CI but passes locally, it is likely a known flake.

Download now (ZIP)

Trending

Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data

Week of Aug 30: 0 new projectsWeek of Sep 6: 0 new projectsWeek of Sep 13: 0 new projectsWeek of Sep 20: 0 new projectsWeek of Sep 27: 0 new projectsWeek of Oct 4: 0 new projectsWeek of Oct 11: 0 new projectsWeek of Oct 18: 0 new projects
Aug 2026Sep 2026Oct 2026
New projects taking a version of this file each week, over the 8 weeks our latest run read: only 0 in all, so this is a hint, not a trend.

Who's talking about sshnet/SSH.NET

The biggest 5 of 80 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 80

Talked about on GitHub and Stack Overflow (80 times).

On GitHub · 50

45 more on GitHub

On Stack Overflow · 30

25 more on Stack Overflow
  • Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.

    Of the Copilot instructions files we read, the 2,297 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.