feat(dotnet11): add process-api-net11 skill for new process APIs - #866
feat(dotnet11): add process-api-net11 skill for new process APIs#866shaikhsharukh wants to merge 5 commits into
Conversation
|
Note This PR is from a fork and modifies infrastructure files ( Changes to infrastructure typically need to be submitted from a branch in Please consider recreating this PR from an upstream branch. If you don't have push access to |
|
@dotnet-policy-service agree |
bb05fea to
29286e7
Compare
|
A short narrated explainer of this PR (dev testing my tool of public repos) - I hope you find it helpful. https://www.lenzon.ai/viewer/cmrb1zapc000o14os7auramuh?voice=google-chirp3 |
Thanks for this contribution, @shaikhsharukh! 🎉 I verified every API in this skill against Before we run evals and move toward merge, though, the 1.
2. 3. Static method signatures. 4. Example 1 won't compile. 5. Example 3 won't compile. For reference, Example 2 ( Once the signatures and examples are aligned with the ref assembly, we'll kick off evals and continue the review. Thanks again for contributing! 🙏 |
8c1066b to
2ae8051
Compare
|
I have aligned the skill definitions and examples with the
|
There was a problem hiding this comment.
Follow-up review — API accuracy re-verified + eval-hardening suggestions
Thanks for the fixes, @shaikhsharukh. I re-checked everything and ran a deeper evaluation pass. Summary below; concrete suggestions are inline on eval.yaml.
1. API accuracy — all confirmed ✅ (proven)
I re-verified every signature in SKILL.md against the current dotnet/runtime main reference assemblies. All five items from the earlier review are now correct: the tuple-returning ReadAllText/ReadAllTextAsync → (string StandardOutput, string StandardError), streaming ReadAllLinesAsync → IAsyncEnumerable<ProcessOutputLine>, RunAndCaptureText(Async) → ProcessTextOutput, and KillOnParentExit. Content looks accurate.
2. Does the skill actually help? — yes, in plugin/deployment mode (proven, scoped)
I hardened the eval to use intent-only prompts (never naming the API) and ran it with skill-validator (--runs 5, judge = claude-opus-4.6). In the whole-plugin configuration (how the skill actually ships), it produced large, low run-to-run variance (CV 1–6%) gains on its target APIs vs a no-skill baseline:
| Scenario | Baseline | With skill |
|---|---|---|
Run + capture (RunAndCaptureText) |
1.8 / 5 | 4.2 / 5 |
Full read (ReadAllText tuple) |
1.0 / 5 | 4.2 / 5 |
Stream lines (ReadAllLinesAsync) |
1.4 / 5 | 4.2 / 5 |
The no-skill baseline reached for the pre-.NET-11 pattern (StandardOutput.ReadToEndAsync() + Task.WhenAll); the judge noted it "didn't even attempt to research what new APIs .NET 11 offers." So the skill is teaching genuinely non-obvious APIs — that's its value.
3. Honest caveat — the blended eval verdict is not green
Being transparent: the validator's official pass metric doesn't clear the 0.10 bar (this skill scored 0.065). The plugin-mode wins above are real, but the isolated single-skill arm shows only small lift and the skill roughly doubles output tokens — both of which the weighted score penalizes. So it's a strong deployment-mode signal with a failing blended score; flagging for maintainers to weigh rather than claiming a clean pass.
4. Suggested eval improvements (inline suggestions)
- Strengthen the run+capture assertions to require both
.StandardOutputand.StandardErrorand reject the old event model. - Add two scenarios that hit the harder, wrong-signature-prone surface — the tuple-returning
ReadAllTextand streamingReadAllLinesAsync/await foreach. These are where the skill adds the most measurable value. - Add a subtle
net10.0non-activation negative (the new APIs are net11-only). - The existing
KillOnParentExitscenario is fine as coverage, but note it shows ~0 marginal lift — the base model already emits it correctly — so it isn't what demonstrates the skill's value.
cc @lewing @SamMonoRT — would appreciate your read on point 3: the deployment-mode gains are real and stable, but the blended eval score doesn't clear the gate. Is the plugin-mode evidence enough to accept, or do you want the eval reworked to a clean green first?
… tests per reviewer suggestions
|
I have applied all of the suggested evaluation improvements:
|
|
/evaluate |
|
❌ Evaluation did not complete successfully (the evaluate job reported |
|
@eiriktsarpalis could you please review this PR? You did the deepest review on the closely analogous #535 (new dotnet11 plugin skill + evals), so your feedback here would be much appreciated. |
|
It might be best if @adamsitnik took a look. |
|
@adamsitnik will review once back from vacation. Please don't merge without his approval. |
|
@adamsitnik , @SamMonoRT : Gentle ping on reviewing the changes here. |
|
/evaluate |
|
👋 Two ways to run it:
|
|
/evaluate 630086d |
|
🔒 Secret-backed evaluation is disabled for fork PRs. A maintainer must review and promote the change to a trusted repository branch before running |
adamsitnik
left a comment
There was a problem hiding this comment.
@shaikhsharukh big thanks for your contribution! PTAL at my comments.
| ## When to Use | ||
|
|
||
| - Running or orchestrating external processes in a .NET 11 (or later) project. | ||
| - Needing to start a process, wait for it to exit, and capture its output/error streams without risking deadlocks (`Process.RunAndCaptureTextAsync`). |
There was a problem hiding this comment.
nit: we provide sync and async overloads
| - Needing to start a process, wait for it to exit, and capture its output/error streams without risking deadlocks (`Process.RunAndCaptureTextAsync`). | |
| - Needing to start a process, wait for it to exit, and capture its output/error streams without risking deadlocks (`Process.RunAndCaptureText[Async]`). |
| - Running or orchestrating external processes in a .NET 11 (or later) project. | ||
| - Needing to start a process, wait for it to exit, and capture its output/error streams without risking deadlocks (`Process.RunAndCaptureTextAsync`). | ||
| - Wanting to ensure child processes are automatically terminated when the parent process exits (`KillOnParentExit`). | ||
| - Requiring trimmer-friendly and NativeAOT-compatible process creation via `SafeProcessHandle`. |
There was a problem hiding this comment.
The wording needs a bit more specific. Process itself is NativeAOT-compatible, it's just that with SafeProcessHandle the user gets the smallest possible size on disk (so it's more of an optimization)
| ## When Not to Use | ||
|
|
||
| - The project targets .NET 10 or earlier — these APIs are not available before .NET 11. | ||
| - Running simple shells where custom execution code is unnecessary. |
There was a problem hiding this comment.
I am not a native speaker, so please take it with a grain of salt. But overall I do believe that the new APIs simplify the code a lot, so I would recommend them even for simple shells.
| <TargetFramework>net11.0</TargetFramework> | ||
| ``` | ||
|
|
||
| ## New APIs & Convenience Methods |
There was a problem hiding this comment.
Each of these methods is a new API, some are also convenience methods. I would just call it New APIs
| ## New APIs & Convenience Methods | |
| ## New APIs |
| ### High-Level Convenience APIs (Static Methods) | ||
|
|
||
| #### `Process.Run` / `Process.RunAsync` | ||
| Starts a process and waits for it to exit, returning the exit status. Does not capture standard output or error. |
There was a problem hiding this comment.
We need to mention that it also allows the users to discard the output/error by providing silent: true and internally redirecting std handles to NUL device.
| ``` | ||
|
|
||
| #### `StartDetached` | ||
| Starts the process detached from the parent's terminal or job session, ensuring it survives the parent's exit. |
There was a problem hiding this comment.
When set to true, the std handles are by default redirected to NUL device. So the child process does not keep the parent process console/terminal resources alive.
|
|
||
| if (result.ExitStatus.ExitCode == 0) | ||
| { | ||
| Console.WriteLine($"Git Output: {result.StandardOutput.Trim()}"); |
There was a problem hiding this comment.
There is no need to use Trim here.
| Console.WriteLine($"Git Output: {result.StandardOutput.Trim()}"); | |
| Console.WriteLine($"Git Output: {result.StandardOutput}"); |
| using System.Threading.Tasks; | ||
|
|
||
| // Run 'git status' and capture output (arguments passed as list) | ||
| ProcessTextOutput result = await Process.RunAndCaptureTextAsync("git", ["status"]); |
There was a problem hiding this comment.
People tend to use async for apps that absolutely don't benefit from it (scalability, cancellation support etc). I think it's better to use non-async overload for such simple examples. So AI-written code is simple and does not pay for the price of using async
| ProcessTextOutput result = await Process.RunAndCaptureTextAsync("git", ["status"]); | |
| ProcessTextOutput result = Process.RunAndCaptureText("git", ["status"]); |
|
|
||
| var startInfo = new ProcessStartInfo("dotnet", ["run", "--project", "BackgroundWorker.csproj"]) | ||
| { | ||
| KillOnParentExit = true // Auto-teardown when this parent process exits |
There was a problem hiding this comment.
| KillOnParentExit = true // Auto-teardown when this parent process exits | |
| KillOnParentExit = OperatingSystem.IsWindows() || OperatingSystem.IsLinux() // Auto-teardown when this parent process exits |
| ```csharp | ||
| using System.Diagnostics; | ||
|
|
||
| var startInfo = new ProcessStartInfo("dotnet", ["run", "--project", "BackgroundWorker.csproj"]) |
There was a problem hiding this comment.
nit: subjective: no need to use var
| var startInfo = new ProcessStartInfo("dotnet", ["run", "--project", "BackgroundWorker.csproj"]) | |
| ProcessStartInfo startInfo = new("dotnet", ["run", "--project", "BackgroundWorker.csproj"]) |
Resolves issue #649 by adding a new skill
process-api-net11for the newSystem.Diagnostics.ProcessAPIs introduced in .NET 11.This skill guides coding agents on using the new convenience one-liners, reliable deadlock-free output reading, and parent-child process lifetime properties. Evals have been included and verified using the skill-validator.