Vercel Composition Patterns
supabase/supabase
React composition patterns that scale. An agent skill from supabase/supabase.
How to align the Go FFI wrapper to a new libhegel (hegel-c) release.
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install hegeldev/hegel-go align-libhegel --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/align-libhegel .claude/skills/align-libhegel && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .claude/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegelType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install hegeldev/hegel-go align-libhegel --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/align-libhegel .agents/skills/align-libhegel && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .agents/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install hegeldev/hegel-go align-libhegel --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/align-libhegel .cursor/skills/align-libhegel && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .cursor/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/hegeldev/hegel-go.git --path .claude/skills/align-libhegel--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install hegeldev/hegel-go align-libhegel --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/align-libhegel .gemini/skills/align-libhegel && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .gemini/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install hegeldev/hegel-go align-libhegelInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/align-libhegel .github/skills/align-libhegel && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .github/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add hegeldev/hegel-go --skill align-libhegel -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install hegeldev/hegel-go align-libhegel --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hegeldev/hegel-go.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/align-libhegel .opencode/skills/align-libhegel && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "align-libhegel" agent skill from https://github.com/hegeldev/hegel-go/tree/main/.claude/skills/align-libhegel into .opencode/skills/align-libhegel/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "align-libhegel", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
align-libhegelHow to align the Go FFI wrapper to a new libhegel (hegel-c) release.
Align Libhegel is an agent skill from hegeldev/hegel-go. How to align the Go FFI wrapper to a new libhegel (hegel-c) release. Use when updating to the latest libhegel release or aligning an explicitly requested version, when just check fails with a symbol-resolution or version-mismatch error against libhegel, or whenever the hegel-c C API in hegel.h has changed and the Go bindings need to catch up.
Its SKILL.md is about 5.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development. The repository describes itself as: Property-based testing for Go. The licence is MIT.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 4eb3241. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
justgocurlFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
raw.githubusercontent.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
GH_TOKENGITHUB_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Align Libhegel loads about 5.8k tokens when it runs. Until then it costs about 90 tokens; SKILL.md has 2,788 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from hegeldev/hegel-go at commit 4eb3241, republished under its MIT licence (© hegeldev). 2,788 words, ~5,756 tokens.
.claude/skills/align-libhegel/SKILL.md (or your agent's skills folder).libhegel is a Rust cdylib built from hegel-rust's hegel-c crate. hegel-go
calls it via purego FFI. When the pinned version changes, the C API in
hegel-c/include/hegel.h may have added, removed, renamed, or re-typed symbols,
and the low-level wrapper in internal/libhegel/ must be re-aligned. The main
hegel package's exported API must not change as a result — only the
internal binding layer — except when libhegel removes an API. In that case,
remove the corresponding API from the public Go package too. Do not preserve it
with a compatibility shim, emulation, or another workaround after its upstream
libhegel support is gone.
Within that binding layer, the wrapper API should track the C API. When a
C function gains a parameter, plumb it through the internal/libhegel wrapper
method (Settings.RunStart, …) rather than hardcoding a constant inside the
wrapper — the wrapper's exported signature is meant to mirror the C signature.
Any behavior-preserving default for a new optional parameter (a NULL callback,
a nullable pointer, a 0-means-default flag) belongs in the package-hegel
callers (runner.go, …), which pass 0/NULL — not baked into the wrapper.
This keeps the binding honest (a future caller can supply a real value) while
holding the hegel package's public API stable. Example: hegel_output_callback_t
added (callback, user_data) to hegel_run_start; the wrapper takes both and
the runner passes 0, 0.
Every fallible libhegel call follows one convention, and the whole wrapper is shaped around it:
hegel_context_t (an error-reporting context).Error result code (OK is 0; failures are
negative — E_INVALID_HANDLE, E_INVALID_ARG, …).OK return, the human-readable message is read back from the context
via hegel_context_last_error.So symbols (the loaded library) is immutable and shared across goroutines,
while the per-call error state lives on a *Context. The wrapper threads a
*Context through every method and funnels every call through two helpers:
ctx.invoke(op, fn) — runs fn(ctxT), and if it returns non-OK, reads
hegel_context_last_error and wraps it into a Go error.allocate(ctx, op, new, free) — invoke for handle constructors: maps a
zero out-handle to a nil result (the engine's "no object" sentinel, e.g. a
finished run) and registers a GC cleanup that calls free.Start by running just vendor-libhegel to vendor the latest stable libhegel
release unless the user explicitly specifies a version. The existing pin in
internal/libhegel/version.go is the starting state, not the requested target.
For an explicit version, run just vendor-libhegel <version-or-tag> instead.
The command accepts bare versions, new tags such as libhegel-v0.42.1, and
legacy tags such as v0.37.1. It downloads and checksum-verifies the binaries
and updates hegelVersion. It uses public GitHub HTTP endpoints; gh login is
not required (an optional GH_TOKEN or GITHUB_TOKEN supports CI rate limits).
Record the actual tag printed by the vendoring command. Native packages in
hegel-rust have independent release versions, so the repository's overall
latest release is not necessarily the latest libhegel. Do not assume a tag is
v<VERSION> or derive the target from a native package release.
Fetch the header from that exact tag, and confirm it exists before editing:
curl -fsSL https://raw.githubusercontent.com/hegeldev/hegel-rust/<ACTUAL_TAG>/hegel-c/include/hegel.hIf resuming with only a pinned version, query the GitHub release API for
libhegel-v<VERSION> and, if absent, v<VERSION>; use the returned tag_name
and verify its assets include libhegel binaries. Keep that resolved tag with
the header for the independent audit in §8.
just check vendoredjust check runs integration tests (TestLoadLibVersion, TestLibhegelEndToEnd)
against the real library, and TestLoadLibVersion asserts the loaded lib
reports exactly hegelVersion. You need a libhegel at that exact version, and
the simplest way to get it is to let the loader use the vendored binary:
just check vendoredAlways use vendored mode for this work — never a local build. The
vendored mode leaves HEGEL_LIBHEGEL_PATH unset, so the loader materializes
the go:embed'd vendored binary for hegelVersion (under
internal/libhegel/libs/, refreshed by just vendor-libhegel) into the cache.
A plain just check would instead build whatever the sibling ../hegel-rust
checkout happens to be on (likely an older tag, since you've just bumped the
version), point HEGEL_LIBHEGEL_PATH at that stale .so, and fail the version
test. Don't touch the checkout; the vendored binary is always the right version.
The cached library lands at:
${XDG_CACHE_HOME:-$HOME/.cache}/hegel-go/libhegel/<VERSION>/libhegel-linux-amd64.soWhen you need the symbol table, run nm -D against that cached .so — no
build required. Use the exact pinned version so an older or newer cached release cannot
be selected:
LIB="${XDG_CACHE_HOME:-$HOME/.cache}/hegel-go/libhegel/<VERSION>/libhegel-linux-amd64.so"
nm -D "$LIB" | grep '^.* T hegel_' | sortThe nm output is ground truth for which hegel_* symbols exist — diff it
against the registration table in tryOpen (libhegel.go). A symbol the wrapper
registers but the lib no longer exports makes registerSymbols fail and
every integration test dies at load.
internal/libhegel/libhegel.goWalk every C declaration and check it against the wrapper. Categorize each:
symbols field, its registration-table
entry, its stub.go closure, and any wrapper method. If it backs an exported
API in the main hegel package, remove that public API and its callers too;
do not add compatibility code that recreates or retains an API libhegel has
removed.hegel_run_result_passed, a bool, became
hegel_run_result_status, a hegel_run_status_t written through an out-param)
→ update the field signature, the registration name, the wrapper method, and
the stub.go closure's signature/out-param handling.symbols field, a registration entry, a wrapper method,
a stub.go closure, and a test (see §5).Error return,
produced value through a trailing out-pointer. The symbols field type and the
wrapper method change together (stub.go adapts on its own — see §4.3). A new
arg must be plumbed through the wrapper method's signature, not hardcoded
inside the wrapper. If it is an optional arg with a behavior-preserving
default (a NULL callback, a nullable pointer, a 0-means-default flag), leave
the wrapper faithful and pass the default from the package-hegel callers
(see the charter note in §intro). Do not silently bury a default in the
wrapper — that hides the new capability and the §8 audit cannot tell a
deliberate default from an oversight.HEGEL_LABEL_*, or a reordered
hegel_status_t) → update the Go const block. Binding-invented labels that
aren't in upstream (LABEL_COMPOSITE, LABEL_STATEFUL) must be renumbered to
sit past the last upstream value so they can't collide.hegel_settings_set_mode(…, hegel_mode_t mode) became (…, uint32_t mode);
same for set_backend, set_verbosity, mark_complete's status) → the Go
enum's base type must mirror the parameter's exact width and signedness
literally, even though it's ABI-transparent. Change type Mode int32 to
type Mode uint32 so it matches the uint32_t param, not the (still-signed)
C enum it descends from. This is a real ABI difference to encode even
though purego marshals a signed and an unsigned 32-bit value into the argument
register identically for the small non-negative values these enums hold — so
the integration tests pass either way and a mismatch will not be caught by
the test suite; only a literal read of the header catches it. A base-type
change needs a go generate ./internal/libhegel (§4), but the generated
_string.go is usually byte-identical (the index assertions and string tables
don't depend on signedness). Note the asymmetry: a value written through an
out-param typed as the enum pointer (hegel_run_status_t *, i.e. RunStatus)
is not widened and keeps mirroring the enum (int32).These must stay consistent or the build/coverage breaks. In practice only the
first two are hand-edited for a signature change; stub.go is reflection-driven
and adapts on its own (item 3), and the wrapper method (item 4) changes only when
the call shape does:
libhegel.go — symbols struct: one func-typed field per C symbol.
Mirror the C signature exactly: func(ctxT, <args>, <*outParam>) Error for a
fallible call. The two exceptions are the C functions that return a value
directly rather than through a result code — only hegel_context_last_error
(func(ctxT) string) currently does this.
libhegel.go — registerSymbols table in tryOpen: {"hegel_x", &syms.x}.
stub.go — reflection-driven, usually needs no edit: Stub(tb, returns ...any) builds a symbols by reflection — it walks the struct and installs a
reflect.MakeFunc closure on every func-typed field, then returns a
*Context. Because the closures are synthesized from each field's type at
runtime, adding, removing, reordering, or retyping a symbols field needs no
change to stub.go — it adapts automatically. Each synthesized
closure recognizes its out-params structurally, not by name: an out[T]
argument by reflect.Type identity, or a pointer-to-~uintptr as a produced
handle. Every non-pointer argument (a by-value scalar, a string, or the
always-NULL outputCallbackT / user_data args) is treated as an input and
consumes no scripted return value. Destructors (field name contains
Free) are detected and auto-free their handle, scripting no return. Values
are supplied by the caller via returns ...any and popped in strict call
order by a single retval() helper. So the thing that moves in lockstep with a
signature change is not stub.go but each test's returns ...any list when a
symbol's output type or call order changes (see §5) — a new input arg
that consumes no return value (like the NULL callback) needs no returns
change either.
libhegel.go — wrapper method: a thin, typed Go method that threads a
*Context. Handle constructors live on Context (e.g. SettingsNew) or on
the parent handle (e.g. Settings.RunStart, Run.NextTestCase) and go
through allocate(ctx, op, new, free). Other fallible calls go through
ctx.invoke(op, fn). Reader methods (Result.Status, Result.FailureCount,
Failure.Origin, …) use the reusable out* scratch fields on the wrapper
struct (TestCase, Result, Failure) so the hot per-draw path doesn't
allocate a fresh out-param on every call.
A pointer to a string is not a valid Go wrapper API choice. Keep nullable
pointers where required in the private symbols ABI signature, but expose
strings idiomatically from wrapper methods. In order of preference:
"" as the absent/remove sentinel when the empty string is not itself
a distinct valid value. This applies to both inputs and outputs."" is a valid value and absence must remain distinguishable, use a
(string, bool) pair: accept value string, present bool for an input, or
return value string, present bool, err error for a fallible output. Keep
the string first, following Go's value/comma-ok convention.Do not expose *string merely to mirror a nullable C char *; translate
between the idiomatic Go representation and NULL at the wrapper boundary.
Enum types are listed in the //go:generate directive at the top of
libhegel.go (currently
-type=Error,Status,Mode,Backend,Verbosity,RunStatus,HealthCheck,Phase,Label).
After adding an enum type or changing any enum constant value:
go generate ./internal/libhegel # uses `go tool stringer`Changed constant values break the compile-time _ = x[CONST-N] assertions in
libhegel_string.go until you regenerate, so this is not optional. Add new enum
types to the -type= list. The generated _string.go is coverage-excluded.
100% per-file coverage is enforced (see the coverage skill). New or changed
wrapper methods need coverage:
runner_test.go —
update those Stub(...) return lists when a symbol's output type or call
order changes (e.g. a bool "passed" value becoming a RunStatus).internal/libhegel/stub_test.go. Build a *Context with
lib := Stub(...), construct the wrapper value in-package against its symbol
table —
tc := &TestCase{pointer: &pointer[testCaseT]{syms: lib.syms, raw: 1}} or
s := &Settings{syms: lib.syms, raw: 1} — and call the method, passing lib
as the *Context. Cover both the happy path and every error branch (a guard
that rejects bad input, like cStringArray's interior-NUL check, needs a test
that trips it).// coverage-ignore. The ratchet in
.github/coverage-ratchet.json auto-tightens when the annotation count drops,
so removing now-covered ignores is free and good.const char * directly → type the field
func(ctxT) string (not *byte/uintptr). Only hegel_context_last_error
does this today.const char ** out-param → type
that argument **byte and read it back with goString, which copies the
NUL-terminated buffer immediately (a NULL pointer — libhegel's "no string" —
yields ""). This is how hegel_version, hegel_run_result_error, and the
failure getters return strings.*settingsT, *runT, *uint64, *bool, *int64, *Collection,
*RunStatus), never as the return value — the return is always the Error
code.keepalive return value or sprinkle runtime.KeepAlive. The GC keeps Go
memory reachable for the duration of a call as long as it is passed as a
typed pointer (*byte, **byte, *Date, …) rather than flattened to a
uintptr. A typed pointer argument is a live root through the call, and the
GC traces transitively from it (a **byte pins the pointer array and every
buffer its elements point at). Memory is lost only if you drop to uintptr —
then the GC can't see it and may free/move it mid-call. So a helper that
produces a C-facing pointer should return just (ptr, len); a separate
keepalive slice is a code smell that means someone thought a typed pointer
needs propping up. It doesn't.const char * argument → pass a Go string; purego manages the memory.const uint8_t * plus a size_t
length, e.g. include_characters) → build it with cString, the inverse of
goString: it aliases the Go string's bytes via unsafe.StringData (no
[]byte copy) and returns (*byte, len). A nil/empty string yields a NULL
pointer. No keepalive — the returned *byte is what keeps the string
reachable (see the bullet above).const char *const * (array of C strings) is not handled automatically.
cStringArrayArg builds a []*byte of NUL-terminated buffers and returns
(cStringArrayPtr, len, err). The typed **byte return keeps both the
pointer array and its buffers reachable across the call — no keepalive. A Go
string may contain an interior NUL but a C string can't, so cStringArrayArg
rejects such input with an error rather than letting C silently truncate it. A
nil slice yields a NULL pointer ("absent"); a non-nil empty slice yields a
non-NULL, length-0 pointer ("the empty set"), which libhegel treats as
distinct.hegel_date_t / hegel_time_t /
hegel_datetime_t as a hegel_generate_* bound) needs explicit padding
fields. purego packs struct fields into argument registers sequentially by
field size and only flushes an eightbyte at an exact 64-bit boundary — it
does not honor the struct's natural alignment padding. So a Go struct whose
C counterpart has interior or trailing padding (like hegel_time_t, where
microsecond sits at offset 4 after a 1-byte pad) must spell that padding out
as real blank fields (_ uint8, _ uint16, …) at the right offsets, or the
fields land in the wrong registers and the C side reads garbage (the classic
symptom: a drawn bound like 23:59:59 arriving as 59:63:66). Add the padding
directly to the exported struct — the same explicit layout also matches C in
memory, so one struct type serves both the by-value inputs and the pointer
output, with no separate ABI/conversion type. Blank padding fields marshal
fine (purego reads them as their zero value). Structs of two eightbytes or
fewer pass in registers; a //go:generate-free way to sanity-check a new one
is a throwaway real-lib draw asserting the bound round-trips. This affects only
by-value struct arguments; a struct written through an out-pointer
(*Date) uses the natural in-memory layout and needs no special handling
beyond the shared padded definition.just check vendored # lint + check-docs + test against the vendored binaryUse vendored mode here too (see §2) — it guarantees the tests run against the
vendored binary, not a stale local build.
Confirm the version smoke test actually ran against the real lib (not skipped):
go test -run 'TestLoadLibVersion|TestLibhegelEndToEnd' -v ./internal/libhegel/The steps above are done by the same context that made the edits, so they share
its blind spots: a symbol you never noticed in the header is a symbol you also
won't notice is unbound. Close that gap with a fresh-context audit as the
final gate. Launch a separate agent (Task tool, subagent_type: "general-purpose") that has not seen your edits and whose only job is to diff
the header against the binding and report anything missing.
Give the agent a self-contained prompt — it starts with no context, so spell out the version and actual release tag, the two files to compare, and the exact output you want:
Audit the libhegel FFI binding for completeness against the C header. Do NOT
edit anything — this is a read-only verification.
1. Read the pinned version from internal/libhegel/version.go (hegelVersion).
2. Independently verify that release tag <ACTUAL_TAG> corresponds to the pin
using the GitHub release API and its libhegel assets. Fetch its header:
curl -fsSL https://raw.githubusercontent.com/hegeldev/hegel-rust/<ACTUAL_TAG>/hegel-c/include/hegel.h
Tags may use libhegel-v<VERSION> or legacy v<VERSION>; do not assume a prefix
or substitute the repository-wide latest native package release.
3. Extract every `hegel_*` function declared in the header.
4. Cross-check each against internal/libhegel/libhegel.go: it must have (a) a
field in the `symbols` struct, (b) an entry in the `registerSymbols` table
in `tryOpen`, and (c) a wrapper method (or a documented reason it has none).
Also flag any registered symbol that is NOT in the header (a stale binding
that would break `registerSymbols` at load).
5. For every symbol, confirm the Go field signature matches the C prototype
under the context-based ABI (ctx first, Error return, produced values via
trailing out-params).
6. Check every integer parameter's width AND signedness against the C type,
including enum-typed params. A C param typed `uint32_t` (even one that
carries a semantically-enum value, e.g. `hegel_mode_t`/`hegel_status_t`
values passed through a widened `uint32_t` slot) must be bound by a
Go type whose base is `uint32`, not `int32` — flag a signed Go enum
bound to an unsigned C param as SIGNATURE-MISMATCH. This mismatch is
invisible to the runtime tests (purego marshals both identically for small
values), so this literal-read check is the only thing that catches it.
7. For every parameter that is NEW in this version (present in the header
prototype but absent from the prior binding), check the corresponding
`internal/libhegel` wrapper method: is the new arg forwarded through the
wrapper's own signature, or hardcoded to a constant inside the wrapper? A new
arg hardcoded inside the wrapper (rather than plumbed to the wrapper signature
and defaulted at the package-`hegel` caller) is a BURIED-DEFAULT — flag it.
This is a design-policy check, not an ABI failure.
Report a table of every header function with OK / MISSING / SIGNATURE-MISMATCH /
BURIED-DEFAULT, and a final verdict line. List discrepancies explicitly; do not
fix them.The agent's report is the gate: if it comes back clean, the alignment is
complete. If it flags a MISSING or SIGNATURE-MISMATCH, return to §3–§5,
fix it, and re-run this gate. This is a genuine independent check only because
the agent rederives the header→binding mapping from scratch — do not paste your
own diff or conclusions into its prompt.
© hegeldev, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/align-libhegel of hegeldev/hegel-go.
Open the folder on GitHubat commit 4eb3241
Align Libhegel next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Align Libhegel this skillhegeldev/hegel-go | 102 | — | ~5.8k | Automated safety check: Pass | MIT | |
| Vercel Composition Patternssupabase/supabase | 111k | 59 repos | ~726 | Automated safety check: Pass | MIT | |
| Finishing a Development Branchobra/superpowers | 296k | 5 repos | ~1.9k | Automated safety check: Pass | MIT | |
| Typescript Advanced Typesrolling-scopes/rsschool-app | 10k | 25 repos | ~4.2k | Automated safety check: Pass | MPL-2.0 | |
| PR Babysitteropeninterpreter/openinterpreter | 69k | 3 repos | ~4.2k | Automated safety check: Pass | Apache-2.0 | |
| Code Review ChecklistshareAI-lab/learn-claude-code | 78k | 5 repos | ~1.1k | Automated safety check: Pass | MIT |
supabase/supabase
React composition patterns that scale. An agent skill from supabase/supabase.
obra/superpowers
Walks the last step of a branch: confirm tests pass, detect the git environment, ask how to integrate, carry out your choice and clean up the worktree.
rolling-scopes/rsschool-app
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications.
openinterpreter/openinterpreter
Watches an open GitHub pull request until it merges, handling review comments, diagnosing CI failures and retrying flaky checks along the way.
shareAI-lab/learn-claude-code
Reviews code against a five-part checklist covering security, correctness, performance, maintainability and testing, and reports findings in a fixed format.
onyx-dot-app/onyx
Iteratively improves a PR (GitHub), MR (GitLab), or shelved changelist (Perforce) until Greptile gives it a 5/5 confidence score with zero unresolved comments.
hegeldev/hegel-go
Changelog style guide for writing RELEASE.md files. An agent skill from hegeldev/hegel-go.
hegeldev/hegel-go
Review your own changes before creating a pull request. An agent skill from hegeldev/hegel-go.
hegeldev/hegel-go
How to approach code coverage in this project. An agent skill from hegeldev/hegel-go.
hegeldev/hegel-go
Go concurrency patterns and pitfalls for this codebase. An agent skill from hegeldev/hegel-go.
Categories
How to align the Go FFI wrapper to a new libhegel (hegel-c) release. Align Libhegel is an agent skill from hegeldev/hegel-go. How to align the Go FFI wrapper to a new libhegel (hegel-c) release.
Align Libhegel fits situations like: updating to the latest libhegel release; aligning an explicitly requested version; just check fails with a symbol-resolution; version-mismatch error against libhegel.
Run `npx skills add hegeldev/hegel-go --skill align-libhegel -a claude-code`. Or copy the skill folder (.claude/skills/align-libhegel in hegeldev/hegel-go) into .claude/skills/align-libhegel in your project. Claude Code loads it when a task matches its description.
Run `npx skills add hegeldev/hegel-go --skill align-libhegel -a codex`. Or copy the skill folder (.claude/skills/align-libhegel in hegeldev/hegel-go) into .agents/skills/align-libhegel in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add hegeldev/hegel-go --skill align-libhegel -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/align-libhegel, .gemini/skills/align-libhegel, .github/skills/align-libhegel and .opencode/skills/align-libhegel in your project.
Going by SKILL.md and its folder, Align Libhegel needs the command-line tools its instructions call (just, go and curl) and credentials named GH_TOKEN and GITHUB_TOKEN. Our summary lists: A credential in GITHUB_TOKEN.
SKILL.md names 1 domain. In commands or code: raw.githubusercontent.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Align Libhegel is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.8k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Align Libhegel: Vercel Composition Patterns (supabase/supabase, 111k stars), Finishing a Development Branch (obra/superpowers, 296k stars), Typescript Advanced Types (rolling-scopes/rsschool-app, 10k stars) and PR Babysitter (openinterpreter/openinterpreter, 69k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
hegeldev (a GitHub organization) maintains it in hegeldev/hegel-go, which has 102 GitHub stars. The repository holds 5 skills in this directory. The repository was last updated on October 7, 2026.
Source: hegeldev/hegel-go on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.