vibeasfunc
Skill0 starsChanged 18 days agoMITView on GitHub
Translate legacy VBA (Excel macros, Word automation, Access modules) into idiomatic functional C# on .NET 10 (or .NET 8 when the deployment is pinned) — replacing imperative loops with LINQ, error codes with Result types, mutable state with immutable records, and side effects pushed to the boundary. Use when the user asks to modernize VBA, convert Excel macros to C#, rewrite a Sub as a pure function, port an .xlsm to a .NET console app, or invokes /vibeasfunc or says "vba to csharp".
In this repository8 other files it gives its agents.
- llms.txtllms.txt
- bpmnemonicSkill
- break-timeSkill
- llms-txtSkill
- memoriaSkill
- poet-commitSkill
- repo-badgesSkill
- seo-geo-auditSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 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.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 47
Not session-based. One-shot per file.
- Distinctive: line 61
Read the VBA macro and answer:
- Distinctive: line 108
Annotate: every non-obvious choice with a comment explaining what the original VBA construct was and why the new shape is better.
- Very specific: line 113
Read-only by default: Never modify the source .xlsm or .bas file.
- Very specific: line 115
Don't guess at COM behavior: If the VBA depends on a specific Excel version's COM quirk, flag it.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill 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
vibeasfunc
ViBeAsFunC — see your VBA anew, as functional C# (.NET 10, or .NET 8).
A modernization skill that ports legacy VBA into idiomatic functional C#. The goal is not a line-by-line transliteration. The goal is to extract the intent of a macro and re-express it in a form that:
- a future reader can understand at a glance,
- a test harness can pin down,
- and a language model can reason about without hallucinating side effects.
Functional C# (records, LINQ, pattern matching, Result types, immutable data) is the right target because it removes the two things that make VBA hard to maintain: mutable shared state and error codes hidden inside Variant returns.
Why this exists
VBA codebases tend to share a few traits:
- One giant
Subthat does input, transformation, and output in a single 800-line block. On Error Resume Nextswallowing failures.Varianteverywhere because nobody wanted to think about types.- Module-level
Publicvariables holding state across calls. - Excel COM interop interleaved with business logic.
A direct translation to imperative C# preserves all of these problems. Functional C# is opinionated enough to force the rewrite to factor cleanly: pure transformation in the middle, side effects at the boundary, types everywhere.
This skill encodes the playbook.
Invocation
The only slash command is /vibeasfunc; Claude Code derives it from the directory name, so /vba2csharp does not exist. Modes are arguments to it.
| Trigger | Behavior |
/vibeasfunc | Default — ask for a VBA file or pasted code, analyze it, propose a translation strategy, then translate |
/vibeasfunc analyze [path] | Read VBA, report constructs found, complexity score, suggested target architecture |
/vibeasfunc translate <path> | Translate one .bas / .cls / .frm / pasted block to functional C# |
/vibeasfunc map <construct> | Look up a specific VBA construct in playbook/constructs.md (e.g. On Error Resume Next, For Each, Variant) |
/vibeasfunc scaffold <name> [--framework net8.0] | Scaffold a target .NET console project structure for the translated code (.NET 10 by default) |
| Natural language: "convert this VBA macro to C#", "rewrite this Sub as a pure function", "modernize this Excel automation" | Same |
Stop / disable
Not session-based. One-shot per file.
Target framework
Translate for .NET 10 (LTS, C# 14) unless the user's deployment is pinned to .NET 8 (C# 12). Ask once if the repo does not say: look for <TargetFramework> in an existing .csproj or an SDK version in global.json. .NET 8 support ends on 10 November 2026, so when the target is .NET 8, say that once in the architecture proposal.
The two targets share almost everything. The differences are a handful of shorter idioms on .NET 10 (CountBy, AggregateBy, Index, LeftJoin, extension properties, the field keyword), listed with their .NET 8 equivalents in playbook/patterns.md §11. Never emit a .NET 10-only API into a .NET 8 translation: it does not compile, and the user finds out at build time.
The translation playbook (5 steps)
This is the core method. Every translation follows it.
Step 1: Identify the boundary
Read the VBA macro and answer:
- What does it read? (sheet ranges, cell values, parameters, MsgBox prompts)
- What does it write? (cells, files, messages, return values)
- What pure transformation happens in between?
The boundary is the imperative shell: COM interop, file I/O, user prompts. Everything else is the functional core.
Step 2: Type the inputs and outputs
Define a record for the input and a record for the output (or a Result<TOk, TError> for fallible operations). Strong types upfront prevent the temptation to mutate.
record InvoiceRow(string Customer, decimal Amount, DateOnly Date);
record InvoiceSummary(decimal Total, int Count, DateOnly Earliest, DateOnly Latest);Step 3: Write the pure function
A static method on a static class. No COM. No file I/O. No mutation of inputs. It takes the input record (or IEnumerable<T> of them) and returns the output record.
public static InvoiceSummary Summarize(IReadOnlyList<InvoiceRow> rows) =>
new(
Total: rows.Sum(r => r.Amount),
Count: rows.Count,
Earliest: rows.Min(r => r.Date),
Latest: rows.Max(r => r.Date));This function is testable in isolation. No Excel needed.
Step 4: Write the boundary glue
Thin wrappers that read the inputs from Excel, call the pure function, and write the outputs back. The glue is allowed to be imperative — that's its job.
Step 5: Replace error handling with Result types
Wherever the VBA used On Error Resume Next or On Error GoTo, the C# uses Result<T, Error> (from FluentResults, LanguageExt, or a hand-rolled discriminated union). Failures become first-class values, not control flow.
Execution flow (what Claude does)
Paths below (scripts/, playbook/, checks/ and the rest) are relative to this skill's directory, ${CLAUDE_SKILL_DIR}, not to the working directory, which is the user's project. Run a script as bash "${CLAUDE_SKILL_DIR}/scripts/<name>.sh" and read reference files from the same place.
- Read the VBA source. Run
scripts/analyze-vba.shif a file is provided to get a construct inventory. - Categorize constructs against
playbook/constructs.mdand call out anything inplaybook/pitfalls.md. - Propose architecture — "this looks like an Excel data-pipeline macro; recommend a .NET 10 console app with ClosedXML for I/O and a pure transformation core". State the target framework. Get user confirmation before translating.
- Translate following the 5-step playbook. Show the translation in chunks: types first, pure function next, boundary glue last.
- Annotate every non-obvious choice with a comment explaining what the original VBA construct was and why the new shape is better.
- Suggest tests for the pure function. Don't write them unless asked.
Safety guardrails
- Read-only by default. Never modify the source
.xlsmor.basfile. Only emit C# code. - Don't run extraction tools that touch the original Excel file. If the user wants VBA extracted, recommend they export modules manually or use
olevbafrom oletools (read-only). - Don't guess at COM behavior. If the VBA depends on a specific Excel version's COM quirk, flag it. Don't silently translate to a
ClosedXMLcall that behaves differently. - Don't translate
Application.OnTime, event handlers, or UserForms without flagging them as architecturally distinct — they need their own pattern (event-driven, MVU, Reactive) and shouldn't be jammed into a console app. - Preserve numeric semantics. VBA
Currencyis fixed-point; map todecimal, neverdouble. VBADateis OLE Automation date; be explicit about timezone assumptions. - Flag external dependencies. References to
Microsoft Outlook 16.0 Object Library,ADODB,Scripting.FileSystemObjectetc. — call them out and recommend modern replacements.
Files in this skill
SKILL.md— this fileplaybook/constructs.md— VBA → functional C# construct mapping tableplaybook/patterns.md— idiomatic functional C# patterns to introduce, including the .NET 8 vs .NET 10 idioms (§11)playbook/excel.md— Excel-specific guidance (COM interop vs ClosedXML/EPPlus)playbook/pitfalls.md— common mistakes when translatingexamples/01-simple-loop.md— For loop → LINQexamples/02-error-handling.md— On Error → Result<T>examples/03-excel-pipeline.md— full Excel macro → functional C# (the hero example)examples/04-string-parsing.md— VBA string surgery → pattern matching + spansscripts/extract-vba.sh— extract VBA modules from .xlsm (best-effort)scripts/analyze-vba.sh— count constructs, score complexityscripts/scaffold-csproj.sh— scaffold a console + core + tests solution;--framework net10.0(default when a 10.x SDK is installed) ornet8.0README.md— short install + quickstart
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.

