From solod
Writes programs in the Solod (So) language - a strict subset of Go that transpiles to C. Use when the user asks to write So code, work with So packages, create So programs, or asks about So language features. Covers the type system, memory model, C interop, standard library, and key differences from Go.
How this skill is triggered — by the user, by Claude, or both
Slash command
/solod:programmingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
So is a strict subset of Go that transpiles to C11. All So code is syntactically valid Go. If a feature isn't listed here, it's not supported.
So is a strict subset of Go that transpiles to C11. All So code is syntactically valid Go. If a feature isn't listed here, it's not supported.
so commandThe so CLI tool transpiles and compiles So programs. Make sure it is installed before use: go install solod.dev/cmd/so@latest.
Commands:
so run <package> - transpile, compile, and run a package. Example: so run . or so run ./myapp.so build <package> - compile a package to an executable. Use -o <file> to set output name (default: package directory basename).so translate <package> - transpile a package to C (generates .h and .c files). Always use -o generated to set output directory to generated.so version - print compiler version.A So project is a standard Go module. Create one with go mod init <name>, then add the So standard library dependency: go get solod.dev@latest.
Not supported: goroutines, channels, closures, anonymous functions, iterators, generic methods (non-inline), recover, fallthrough, type switches, interface-to-interface assertions, delete on maps, dynamic errors, named return values, returning interfaces or arrays from functions.
IMPORTANT: So is a manually managed language. Make sure you avoid typical memory bugs (use-after-free, double-free, memory leaks, etc.) when writing So programs.
| Go type | C type | Notes |
|---|---|---|
int | so_int (int64_t) | |
byte | so_byte (uint8_t) | |
rune | so_rune (int32_t) | |
float64 | double | |
float32 | float | |
bool | bool | |
string | so_String | struct: { const char* ptr; so_int len; } |
[]T | so_Slice | struct: { void* ptr; so_int len; so_int cap; } |
map[K]V | so_Map* | pointer to stack-allocated hash table |
any | void* | not an interface - just a pointer |
nil | NULL | |
error | so_Error | pointer to error struct |
All variables are zero-initialized as in Go.
so_String with ptr and len. Literals wrapped in so_str().
[]byte(string) and string([]byte) are zero-copy (alias original data).[]rune(string) and string([]rune) allocate (stack).string(byte) and string(rune) allocate (stack).+ and += concatenation works but allocates on stack. For large/heap strings, use so/strings.Builder.Plain C arrays. Value types on struct assignment (memcpy).
len() and cap() are compile-time constants.so_Slice.so_Slice with ptr, len, cap. Stack-allocated by default.
make([]T, len) and make([]T, len, cap) allocate on the stack.append() panics if capacity exceeded - no automatic reallocation.so/slices package.(so_Slice){0}.clear zeros elements (length/capacity unchanged). Not supported for maps.s[low:high:max] supported.Fixed-size, stack-allocated, pointer-based (so_Map*). MSI (mask-step-index) hash tables.
make(map[K]V, cap).delete. No resize.m[k] += 1 not supported.so/maps package.bool, float32, float64, string, pointers.func sum(a, b int) int { return a + b }
package_Func in C. Unexported -> static.Only two-value returns in two patterns:
(T, error) pattern:
func divide(a, b int) (int, error) {
if b == 0 { return 0, ErrDivByZero }
return a / b, nil
}
Supported T types: bool, byte, float64, int, int64, rune, string, []T, *T.
Custom struct results for (StructType, error):
type FileResult struct {
val File
err error
}
func open(name string) (File, error) { ... }
(T1, T2) pattern for two values of any supported type:
func divmod(a, b int) (int, int) { return a / b, a % b }
Standard ...T syntax. Can spread slices with s....
Standard Go struct syntax. Supports anonymous structs and inner struct fields.
new() works with types and values:
p := new(point) // *point, zero-initialized
p2 := new(point{1, 2}) // *point with values
n := new(42) // *int with value 42
void* self in C, cast internally.T.method) supported; method values (v.method) not supported.Struct with void* self + function pointers. No runtime type info.
var s Shape = &rect._, ok := s.(*Rect) or r := s.(*Rect) (not both).any/interface{}) = void*.Typed constant groups. Integer and string enums. iota supported for integers.
type Day int
const (
Sunday Day = iota
Monday
Tuesday
)
Sentinel errors only, defined at package level:
var ErrNotFound = errors.New("not found")
==). O(1) operation.fmt.Errorf, no errors.New inside functions, no wrapping.panic() accepts string literal, string variable, or error. No recover.
defer works in function scope and bare block scope only. Not in for or if. Emitted inline in LIFO order.
Each package -> one .h + .c pair. Multiple .go files merged.
static.#include.init() per package allowed (emitted as __attribute__((constructor))).make(), append(), new(), map literals are all stack-allocated.slices.Make, slices.Append, maps.New, mem.Alloc - all take mem.Allocator.nil for allocator to use the system allocator (calloc/realloc/free).so_MaxAllocaSize).Since So code is valid Go, tests use the standard go test toolchain. Functions marked //so:extern have Go stub bodies that serve as test doubles - the Go test runner executes these stubs while the real C implementations are used in the compiled binary.
go test ./...go test -run TestName ./path/to/package//so:extern function bodies are only executed during go test - they are not emitted to C. Write them to return reasonable values for testing.Very limited. Two forms:
#define macros on C side.//so:inline on generic functions) - auto-generates C macros. Restrictions: single return at end, no defer, args may evaluate multiple times. Prefix locals with _.See interop.md for details on both forms.
//so:extern, //so:include, //so:inline, //so:embed, automatic decay, raw C intrinsics, and generic patterns.so/* packages. Use go doc -all solod.dev/so/<pkg> for full API details.Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub solod-dev/ai --plugin solod