
Fsharp
- 15 installs
- 466 repo stars
- Updated July 25, 2026
- managedcode/dotnet-skills
Helps with ai & agent building tasks.
About
fsharp is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- fsharp
- AI & Agent Building
- AI-coding skill
Fsharp by the numbers
- 15 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #11,187 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/managedcode/dotnet-skills --skill fsharpAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 15 |
|---|---|
| repo stars | ★ 466 |
| Last updated | July 25, 2026 |
| Repository | managedcode/dotnet-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
F# for .NET
Trigger On
- the task touches
.fs,.fsx,.fsi, or.fsprojfiles - domain logic benefits from records, discriminated unions, options, results, or exhaustive pattern matching
- generated code needs a strongly typed functional model instead of nullable primitive state
- F# code must interoperate with C# or other .NET libraries
- the repository needs project setup, source ordering, or validation for F# code
Do Not Use For
- C# language feature selection; use
modern-csharp - analyzer-only, formatter-only, or CI-only work with no F# language decisions
- one-off REPL or scripting exploration that does not affect project code; use
fsi - non-.NET functional languages
Project Setup
Use the .NET SDK templates when adding F# projects.
dotnet new classlib -lang "F#" -o src/Domain
dotnet new console -lang "F#" -o src/App
dotnet new xunit -lang "F#" -o tests/Domain.Tests
dotnet sln add src/Domain/Domain.fsproj tests/Domain.Tests/Domain.Tests.fsproj
dotnet add tests/Domain.Tests/Domain.Tests.fsproj reference src/Domain/Domain.fsproj
dotnet buildFSharp.Core is normally supplied by the F# SDK project. Add or pin it explicitly only when the repo has a package policy that requires deterministic package versions.
dotnet add src/Domain/Domain.fsproj package FSharp.CoreSource Ordering
F# compiles files in the order listed in the project file. Define types and modules before files that consume them.
<ItemGroup>
<Compile Include="Domain.fs" />
<Compile Include="Validation.fs" />
<Compile Include="Program.fs" />
</ItemGroup>When adding a file, update the .fsproj intentionally. Do not assume wildcard ordering.
Workflow
1. Inspect the existing .fsproj, .fs, .fsi, and .fsx files to determine compile order, public boundaries, and whether the code is F#-first or C#-facing. 2. Choose the smallest F# model that represents the invariant: records for named product data, discriminated unions for closed state, option for absence, and Result for expected failures. 3. Add or edit source files in dependency order, then update the .fsproj compile list before consumers reference the new code. 4. Review public API shape for .NET interop. Translate F#-specific internal models to DTOs, methods, or Try* patterns when C# callers need a stable surface. 5. Run dotnet build, targeted tests, and any relevant dotnet fsi probes before returning the final result.
Current Upstream Notes
- The refreshed F# overview emphasizes functional-first programming on .NET with records, discriminated unions, pattern matching, units of measure, type providers, and interop. Keep F# guidance domain-model oriented rather than translating C# object patterns mechanically.
- Use
fsifor exploratory scripts, but move durable code into ordered.fsprojfiles before it becomes production behavior.
Practical Patterns
Model State With Records And Unions
Prefer a type that names every valid state over loose strings, nullable values, or parallel booleans.
module Orders
type OrderId = private OrderId of string
module OrderId =
let tryCreate value =
if System.String.IsNullOrWhiteSpace value then
Error "Order id is required."
else
Ok (OrderId value)
type Payment =
| Card of last4: string
| Wire of iban: string
| PurchaseOrder of number: string
type Order =
{ Id: OrderId
Customer: string
Payment: Payment }
let describePayment payment =
match payment with
| Card last4 -> $"card ending {last4}"
| Wire iban -> $"wire transfer {iban}"
| PurchaseOrder number -> $"purchase order {number}"Compose Validation With Result
Return Result<'T,'Error> when callers must handle failure and when failures are part of the domain.
module Pricing
type Price =
private
| Price of decimal
module Price =
let tryCreate amount =
if amount < 0m then
Error "Price cannot be negative."
else
Ok (Price amount)
let value (Price amount) = amount
type Line =
{ Sku: string
Quantity: int
UnitPrice: Price }
let tryCreateLine sku quantity amount =
match Price.tryCreate amount with
| Ok price when quantity > 0 ->
Ok { Sku = sku; Quantity = quantity; UnitPrice = price }
| Ok _ ->
Error "Quantity must be positive."
| Error message ->
Error messageRead And Transform Data
Use pipelines for readable transformations, but stop before the pipeline hides error handling or allocation cost.
open System.IO
let readActiveUsers path =
File.ReadLines path
|> Seq.skip 1
|> Seq.choose (fun line ->
match line.Split(',') with
| [| id; name; "active" |] -> Some {| Id = id; Name = name |}
| _ -> None)
|> Seq.toListWrite A Small .NET Boundary
Make public interop APIs easy for C# callers. Hide F#-specific details behind functions, methods, or DTO records when needed.
namespace Company.Domain
type InvoiceDto =
{ Id: string
Total: decimal
IsPaid: bool }
module Invoice =
let markPaid invoice =
{ invoice with IsPaid = true }Interop Guidance
- Keep F# discriminated unions inside F# boundaries unless C# consumers are expected to understand their generated shape.
- Use records or explicit classes for public cross-language DTOs.
- Use
optioninternally; translate to nullable annotations,Try*methods, orResultat C#-first public boundaries. - Avoid throwing for expected domain failures. Use exceptions for unexpected infrastructure failures.
- Prefer
task { }orTask-returning APIs at .NET interop boundaries; useAsync<'T>when the code is F#-first.
Review Checklist
- The
.fsprojcompile order matches dependency order. - All union cases are handled explicitly; wildcard branches are justified.
- Public types have stable names and shapes for downstream .NET consumers.
- Domain failures are modeled with
optionorResult, not undocumentednull. - Pipelines remain readable and do not hide repeated enumeration of expensive sequences.
- Tests cover at least one success and one failure path for each domain constructor or validator.
Validate
Run the narrowest relevant checks after changes:
dotnet build
dotnet test
dotnet fsi scripts/check.fsxIf adding a new F# file, also inspect the project file diff to confirm the compile order is deliberate.
Sources
- https://learn.microsoft.com/dotnet/fsharp/what-is-fsharp
- https://learn.microsoft.com/dotnet/fsharp/get-started/get-started-command-line
- https://learn.microsoft.com/dotnet/fsharp/language-reference/discriminated-unions
- https://learn.microsoft.com/dotnet/fsharp/language-reference/pattern-matching
- https://learn.microsoft.com/dotnet/fsharp/language-reference/results
{
"version": "1.0.1",
"category": "Core",
"packages": [
"FSharp.Core"
]
}