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
- Distinctive: line 66
StyleCop is enforced: Follow existing file conventions:
- Very specific: line 79
Use the existing exception hierarchy.
- Very specific: line 106
Prefer ReadOnlyMemory<byte> / Memory<byte> over byte[] in new protocol-layer code.
- Very specific: line 107
Do not expose mutable collections directly.
- Very specific: line 113
Use async Task / async ValueTask with CancellationToken for all new async methods.
- Very specific: line 115
Prefer TaskCompletionSource<T> to bridge event-driven or callback-based code into the async model.
- Very specific: line 116
Never block inside async code with .Result or .Wait() — this can cause deadlocks on synchronization-context-bound callers.
- Very specific: line 117
Use ConfigureAwait(false) in library code (this is a class library, not an app).
- Very specific: line 164
Run with dotnet test like any other project once Docker is available.
- Distinctive: line 181
Add unit tests for every new public method and every non-trivial internal method.
- Very specific: line 182
Test both the happy path and error/edge cases (e.g., null arguments, disposed state, cancellation).
- Distinctive: line 184
Do not remove or weaken existing tests.
- Very specific: line 191
Prefer ArrayPool<byte>.Shared or MemoryPool<byte>.Shared over allocating new byte[] in protocol encoding/decoding.
≈ “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.
Files
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
| Area | Technology |
| Language | C# (LangVersion=latest) with #nullable enable everywhere |
| Runtimes | .NET Framework 4.6.2, .NET Standard 2.0, .NET 8+, .NET 9+, .NET 10+ |
| Cryptography | BouncyCastle (BouncyCastle.Cryptography) |
| Logging | Microsoft.Extensions.Logging.Abstractions (ILogger/ILoggerFactory) |
| Testing | MSTest v4, Moq, Testcontainers (Docker for integration tests) |
| Build tooling | .NET SDK 10.0.100, Nerdbank.GitVersioning |
| Static analysis | StyleCop.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 abstractionsLarge classes are split into partial class files per concern (e.g., PrivateKeyFile.PKCS1.cs, PrivateKeyFile.OpenSSH.cs).
Naming and style conventions
| Element | Convention | Example |
| Classes, methods, properties | PascalCase | SftpClient, ListDirectory(), IsConnected |
| Private fields | _camelCase | _isDisposed, _sftpSession |
| Interfaces | I prefix + PascalCase | ISftpClient, IChannel |
| Constants / static readonly | PascalCase | MaximumSshPacketSize |
| Local variables | camelCase | operationTimeout, connectionInfo |
StyleCop is enforced. Follow existing file conventions:
#nullable enableat the top of every.csfile.usingdirectives outside the namespace block, grouped withSystem.*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] #endifand add the protected serialization constructor inside the same#ifblock, matching the pattern inSshException.cs. - Surface async errors by storing them in a
TaskCompletionSourceor re-throwing viaExceptionDispatchInfo.Throw()— never swallow exceptions silently. - Raise
ErrorOccurredevents 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,ArgumentOutOfRangeExceptionwith descriptive messages. - Return
IEnumerable<T>for sequences that are already materialized; useIAsyncEnumerable<T>when data streams asynchronously. - Prefer
ReadOnlyMemory<byte>/Memory<byte>overbyte[]in new protocol-layer code. - Do not expose mutable collections directly; use
.AsReadOnly()or copy-on-return.
Async and concurrency
- Use
async Task/async ValueTaskwithCancellationTokenfor all new async methods. - The socket receive loop and keep-alive timer run on dedicated background threads; protect shared state with
lockor the custom internalLocktype used inSession. - Prefer
TaskCompletionSource<T>to bridge event-driven or callback-based code into the async model. - Never block inside async code with
.Resultor.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
Debuglevel. SshNetLoggingConfiguration.WiresharkKeyLogFilePathis 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 testlike 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.,
nullarguments, disposed state, cancellation). - For async methods, test cancellation via
CancellationTokenand timeout behaviour. - Do not remove or weaken existing tests; add new tests instead.
Performance considerations
- SSH.NET is designed for parallelism; avoid introducing
lockcontention on hot paths. - Prefer
ArrayPool<byte>.SharedorMemoryPool<byte>.Sharedover allocating newbyte[]in protocol encoding/decoding. - The
BufferSizeonSftpClientcontrols 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
- Run the unit tests first (
dotnet test test/Renci.SshNet.Tests/) to establish a clean baseline. - Keep changes focused. Small, targeted PRs merge faster. Separate refactoring from behaviour changes.
- Multi-targeting: the library targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET. Use
#if NETFRAMEWORK/#if NETguards for platform-specific code; confirm all TFMs build withdotnet build. - 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.
- Cryptographic changes: consult existing algorithm registration lists (in
ConnectionInfo.csandSession.cs) before adding or removing algorithms. - StyleCop and analyzers: the build treats analyzer warnings as errors in Release/CI mode. Run
dotnet build -c Releaselocally to catch these before pushing. - 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.
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about sshnet/SSH.NET
- Stack Overflow“How to run commands on SSH server in C#?”Stack Overflow · Jun 17, 2015 · 37 votes
- Stack Overflow“Are there any good free .Net network libraries? (FTP, SFTP, SSH, etc.)”Stack Overflow · Mar 24, 2011 · 30 votes
- Stack Overflow“Using "OPENSSH" private key file in string with SSH.NET in C# fails with "invalid private key file"”Stack Overflow · Jan 14, 2021 · 19 votes
- Stack Overflow“Copying or moving a remote file using SSH.NET with C#”Stack Overflow · Aug 29, 2016 · 16 votes
- Stack Overflow“Xamarin. Pair to Mac. Key 'OPENSSH' is not supported”Stack Overflow · Oct 11, 2018 · 11 votes
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
- Jul 7, 2023Support rsa-sha2-256/512 for SFTP uploader — ShareX/ShareX2 reactions · 5 comments
- Sep 8, 2022Unable to connect to ubuntu 22.04 using ssh-rsa — OctopusDeploy/Issues2 reactions · 7 comments
- Aug 12, 2026Bump the nuget group with 2 updates — TheSmokeTeam/QaaS.Framework1 reaction
- Dec 16, 2025dropbear: bump to latest release 2025.89 (CVE-2025-14282, CVE-2019-6111) — openwrt/openwrt1 reaction · 7 comments
- Nov 10, 2025Bump SSH.NET from 2025.0.0 to 2025.1.0 — jas88/RDMP1 reaction
45 more on GitHub
- Aug 10, 2025Don't limit channel window to 500MB — mkj/dropbear1 reaction
- Apr 20, 2024Wrong IDE0055 in combination with CRLF, XML comment and preprocessor directive — dotnet/roslyn1 reaction · 15 comments
- Dec 11, 2023Size of BouncyCastle library — bcgit/bc-csharp1 reaction · 4 comments
- Mar 23, 2023Replaced chilkat proprietary dll with open source ssh.net — LogExperts/LogExpert1 reaction · 1 comment
- Jun 1, 2022Bump SSH.NET from 2016.1.0 to 2020.0.2 — santiagoborjaromero/multissh1 reaction
- Dec 31, 2020Update SSH.NET to version 2020.0.1 — duplicati/duplicati1 reaction · 16 comments
- Oct 28, 2026Bump SSH.NET from 2016.1.0 to 2026.0.0 — vndevpro/MiniProfiler.Integrations0 reactions
- Oct 25, 2026Bump the nuget group with 3 updates — sn109946/win-acme0 reactions · 1 comment
- Oct 23, 2026Bump SSH.NET from 2016.1.0 to 2026.0.0 — rileyseaburg/btcpayserver0 reactions
- Oct 20, 2026Bump the nuget group with 3 updates — Horlabrainmoore/BrainPay-BTCPay-Server-0 reactions · 3 comments
- Oct 18, 2026Bump SSH.NET from 2024.2.0 to 2026.0.0 — towertail/towertail0 reactions
- Oct 18, 2026Bump SSH.NET from 2025.1.0 to 2026.0.0 — NewLifeX/XCoder0 reactions
- Oct 8, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — SBY-TECH/MissionPlanner-gps-config0 reactions
- Oct 7, 2026Bump the nuget group with 1 update — github/gh-gei0 reactions · 2 comments
- Sep 28, 2026Reminder: Revert SSH.NET Vendored dll on new release — cmu-sei/GHOSTS0 reactions
- Sep 19, 2026Bump SSH.NET from 2025.1.0 to 2026.0.0 — darkoperator/Posh-SSH0 reactions
- Sep 18, 2026Bump the nuget group with 1 update — Hawthorne001/azure-libraries-for-net0 reactions
- Sep 17, 2026Bump SSH.NET from 2025.1.0 to 2026.0.0 — sede-open/simple-acme-v2.3.40 reactions
- Sep 17, 2026Bump the nuget group with 1 update — johnnyleevn85/btcpayserver0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — TonyRL/ShareX0 reactions
- Sep 17, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — RotorsAndCams/RAC-MV04-Planner0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — tagatac/duplicati0 reactions
- Sep 17, 2026Bump SSH.NET from 2016.1.0 to 2026.0.0 — bergerMichael/WSU-AMS-General-University-Classroom-Tools0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — congiuluc/gh-gei0 reactions
- Sep 17, 2026Bump SSH.NET from 2025.1.0 to 2026.0.0 — sede-open/simple-acme-v.2.3.4.10 reactions
- Sep 17, 2026Bump the nuget group with 1 update — Breinich/BenchmarkingPortal0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — H1d3r/ProxySU0 reactions
- Sep 17, 2026Bump the nuget group with 3 updates — c1490b-code/win-acme0 reactions
- Sep 17, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — RotorsAndCams/RAC-VORBasedNavigation0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — packfiles/gh-gei0 reactions
- Sep 17, 2026Bump SSH.NET from 2024.2.0 to 2026.0.0 — bcgov/jag-traffic-courts-online0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — naywint3/ShareX0 reactions · 1 comment
- Sep 17, 2026Bump the nuget group with 1 update — seilorjunior/gh-gei0 reactions
- Sep 17, 2026Bump the nuget group with 1 update — Pairs34/FortigateMCP0 reactions
- Sep 17, 2026Bump Microsoft.Extensions.Logging.Abstractions and SSH.NET — TopSwagCode/Dotnet.DeployTool0 reactions
- Sep 15, 2026Bump SSH.NET from 2025.1.0 to 2026.0.0 — dennisreimann/btcpayserver0 reactions
- Sep 8, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — karlgodtliebsen/MissionPlanner0 reactions
- Sep 2, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — RotorsAndCams/MissionPlanner0 reactions
- Sep 1, 2026deps: Bump SSH.NET from 2024.2.0 to 2026.0.0 — jyrmyx/hakchi-cli0 reactions
- Aug 24, 2026Bump SSH.NET from 2016.1.0 to 2026.0.0 — higty/higlabo.netstandard0 reactions
- Aug 23, 2026Bump SSH.NET from 2025.0.0 to 2026.0.0 — Joaoof/formaturas-api0 reactions
- Aug 14, 2026Bump the dotnet-dependencies group with 1 update — lanessear/PalworldHelper0 reactions
- Aug 12, 2026Bump SSH.NET from 2024.2.0 to 2026.0.0 — tracsman/Projects0 reactions
- Aug 12, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — Worldpay/cnp-sdk-for-dotnet0 reactions
- Aug 12, 2026Bump SSH.NET from 2020.0.2 to 2026.0.0 — Wojdakoman/BankUI0 reactions
On Stack Overflow · 30
- Jun 17, 2015How to run commands on SSH server in C#?37 votes
- Mar 24, 2011Are there any good free .Net network libraries? (FTP, SFTP, SSH, etc.)30 votes
- Jan 14, 2021Using "OPENSSH" private key file in string with SSH.NET in C# fails with "invalid private key file"19 votes · 3 answers
- Aug 29, 2016Copying or moving a remote file using SSH.NET with C#16 votes
- Oct 11, 2018Xamarin. Pair to Mac. Key 'OPENSSH' is not supported11 votes · 3 answers
25 more on Stack Overflow
- Aug 31, 2019Randomly getting Renci.SshNet.SftpClient.Connect throwing SshConnectionException9 votes
- Sep 9, 2016Can't install SSH.NET on Visual Studio 2012 Ultimate7 votes
- Dec 29, 2023SSH.Net Async file download6 votes
- Jun 8, 2023Renci.SshNet no longer working when SHA1 disabled and SHA2 enabled6 votes
- Mar 18, 2021Using SSH.NET with strong ciphers5 votes · 1 answer
- Dec 27, 2021SSH.Net SftpClient: do I need to call Disconnect within using block?4 votes
- Aug 7, 2019How can I set a thread or task to automatically abort/cancel after a given time in dotnet core in docker?3 votes
- Oct 9, 2018Changing Key exchange method in SSH.NET3 votes · 1 answer
- Dec 28, 2012sharpssh "session is down" during concurrent connections3 votes
- Oct 24, 2022"Renci.SshNet.Common.SshException: Invalid private key file" when loading SSH private key from configuration string using SSH.NET2 votes
- Aug 20, 2017PasswordVault security when used from Desktop app2 votes
- Jul 27, 2017SSH.NET Library Installation in Visual Studio2 votes · 1 answer
- Oct 10, 2023Renci.SshNet no longer working when SHA1 disabled and SHA2 enabled1 vote
- Aug 2, 2023Create SSH ED25519 key with BouncyCastle for Rency SSH.NET in C#1 vote
- Jun 18, 2023How to create keys for SSH.NET without using ssh-keygen on client-side?1 vote
- Jun 12, 2019How to connect SSH.NET in MongoDB C#1 vote · 1 answer
- Nov 16, 2018Delete files with pattern in remote SFTP directory1 vote
- Jun 14, 2017C# programatically remotely connect to Linux server to connect to Amazon RDS DB1 vote
- May 26, 2017What is the difference between SftpClient.UploadFile and SftpClient.WriteAllBytes?1 vote
- Aug 4, 2016How to send terminal commands to a raspberry pi from a c# application1 vote
- Dec 10, 2009How to communicate with SFTP server1 vote
- Jan 24, 2021C# Renci SshNet The server response contains a null character at position 0x0000002A0 votes
- Feb 27, 2019SshConnectionException from SshNet in C#0 votes
- Feb 13, 2018Does .NET Web Service/WCF Supports file transfer between SFTP Servers?0 votes
- Aug 14, 2017.NET SSH port forwarding0 votes
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
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.

