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:
- Grab a copy of the git repo
- Navigate to the documentation folder
- 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.