Robware Software by Rob

Welcome

Hello, I'm Rob. I'm a senior software engineer at On The Beach. Professionally my focus has been in backend development primarily using C#. In my spare time I spend my time riding bikes or making stuff, typically involving an Arduino.

This website is primarily an outlet for me to write about things which have been technically challenging, either in a professional or personal capacity, though not limited to that.

If you wish to get in contact, then get in touch via my LinkedIn profile.

Latest code commit

Repositorywebsite
Branchmaster
SHAaf77a36611e348a3d86d1c04d57c3b7b55619884
MessageFix null reference issue
Timestamp07:28:17 on Friday the 10th of July 2026

Latest Blog Post

Expanding local LLM capabilities by creating skills from documentation

I've been using OpenCode lately with locally running LLMs with LM Studio, mostly with the Qwen 3.6 35B A3B model. Compared to the likes of Claude, these local models have some significant limitations. One major limitation I was finding with Qwen is that it would always generate FluentAssertions syntax for unit tests despite having Shouldly specified. It seems to understand I want to use Shoudly, but would get stuck generating FluentAssertions syntax. Quite annoying. In order to get around this I decided I'd create a custom skill from the documentation, and then get my agent to explicitly load it.

The steps are pretty basic:

  1. Grab a copy of the git repo
  2. Navigate to the documentation folder
  3. Using OpenCode's own Build agent, tell your LLM to create a skill from the documentation

It really is that simple. I did the same thing with NSubstitute.

~/.config/opencode/skills/shouldly$ tree
.
├── references
│   ├── completeIn.md
│   ├── configuration.md
│   ├── dictionary
│   │   ├── containKeyAndValue.md
│   │   ├── containKey.md
│   │   └── README.md
│   ├── dynamicShould.md
│   ├── enumerable
│   │   ├── allBe.md
│   │   ├── contain.md
│   │   ├── empty.md
│   │   ├── have.md
│   │   ├── oneOf.md
│   │   ├── README.md
│   │   ├── shouldBe.md
│   │   ├── subsetOf.md
│   │   └── unique.md
│   ├── equality
│   │   ├── assignableTo.md
│   │   ├── exampleClasses.md
│   │   ├── greaterLessThan.md
│   │   ├── haveFlag.md
│   │   ├── inRange.md
│   │   ├── matchApproved.md
│   │   ├── notBe.md
│   │   ├── null.md
│   │   ├── ofType.md
│   │   ├── oneOf.md
│   │   ├── README.md
│   │   ├── sameAs.md
│   │   ├── shouldBe.md
│   │   ├── ShouldMatchApprovedChanged.png
│   │   ├── ShouldMatchApprovedInitial.png
│   │   └── trueFalse.md
│   ├── exceptions
│   │   ├── notThrow.md
│   │   ├── README.md
│   │   └── throw.md
│   ├── getting-started.md
│   ├── satisfyAllConditions.md
│   ├── string
│   │   ├── contain.md
│   │   ├── endWith.md
│   │   ├── match.md
│   │   ├── null.md
│   │   ├── README.md
│   │   ├── shouldBe.md
│   │   └── startWith.md
│   └── upgrade
│       └── 3to4.md
└── SKILL.md

I also recommend creating an agent to specialise in software development and explicitly requesting the skill(s) in the agent file's frontmatter:

skills: csharp-developer, shouldly, nsubstitute

I also got it to create documentation on the Seeed Studio XIAO ESP32C3 by telling it to turn the getting started page in to a skill, and also the CAN Bus expansion board, to help with my campervan control system project.

Doing this has significantly improved the accuracy of the output and reduced the number of times it gets stuck in a loop and also reduced the amount of time spent thinking.

Posted on Friday the 10th of July 2026

View more