Just add a .hy file. It's still Go — Hybrid is what Go can safely do.
If you know Go, you already know Hybrid: keep your codebase, keep your tooling, and let the compiler prove your new files race-free — one file at a time.
Quick start · The guarantee · Design · Evidence · Roadmap · Feedback thread
Hybrid is a safety-checked superset of Go. Write .hy files beside your
.go files wherever you want compiler-enforced ownership and cross-task
sharing rules; a checker (written in Rust) verifies them and transpiles your
.hy code to plain, readable Go. Your existing Go stays untouched, your
Go callers don't change, and one build command produces one ordinary binary —
no runtime, no VM, no FFI in the output.
// checkout.hy — a checked file, dropped into an existing Go module
import "rust/regex"
fn validate_email(raw string) (string, error) {
re := regex.must_compile(`^[\w.+-]+@[\w-]+\.[\w.]+$`)
if !re.is_match(raw) {
return "", errors.new("invalid email")
}
return raw, nil
}// main.go — your existing Go code, unchanged
email, err := hybrid.ValidateEmail(raw)hyb build checkout.hy -o myapp # one command: check → emit Go → go build- It's still Go. The output is Go source riding the Go compiler, runtime, GC and scheduler. There is no new runtime to operate and no new deployment story — the binary is a normal Go binary.
- Races become compile errors. In a
.hyfile, sharing mutable state across tasks without an ownership transfer, a channel, or the auditablemanagedhatch is rejected beforego buildever runs — with a fix-it in the message, not a 3 a.m. page. - Incremental. Adopt file-by-file inside an existing Go module. No rewrite, no big-bang migration, no new build culture.
- One build command.
hyb builddrives the pinned Go + Rust toolchains for you. Consumers of a Hybrid package need no Hybrid toolchain at all (example 09: a plaingo runimports a Hybrid-compiled package). - Rust crates, Go ergonomics. A pinned set of Rust crates (serde_json, regex, sha3…) is reachable with Go-shaped error handling and ownership; the boundary is checked like everything else.
The Tier-0 checker is fail-closed at critical boundaries (rule FC, O4.9):
- Every value crossing a
taskspawn or channel send is classified. Values the checker can prove safe — primitives, channels, immutable, ownedmovetransfers, fresh literals with sendable parts — pass. - Values the checker cannot prove — a mutable map shared across tasks, a
borrowed pointer, or anything whose type it cannot resolve — are
rejected (
HYB-E3001/E3002/E3005) with diagnostics that name the value and teach the fix: ascribe the type, route through a channel, or take the hatch knowingly. - Nothing silently passes. The escape hatch —
managed("reason", "category") { ... }— is explicit, linted, greppable, and counted by--report-managed; CI can forbid it entirely with--deny-managed. - Boundary statements inside closures are checked too; Go-API escapes
(a closure handed to
net/http) are outside the checked subset and documented as such, not hidden.
The sharp version of the contract: everything the checker accepts was
proven; everything it can't prove is named. The line-by-line claims table
— including the primitives you should ask about (sync.Pool,
atomic.Pointer, context.Context, finalizers, unsafe, cgo, channel
close) — lives in GUARANTEES.md; the full rules with their
pre-registered evidence live in SPEC-LANGUAGE.md §9; the
honest-claims paragraph (what is not guaranteed — e.g. a managed region
is still Go's DRF-SC story with -race as the backstop) is binding there.
.hy → Rust checker (parse → ownership/sendability/loan checks) → Go
emission → go build. Rust-crate calls ride a generated bridge: a Rust
staticlib linked into the same binary through assembly trampolines that
skip the cgo runtime.
| design question | answer | status |
|---|---|---|
| What can Hybrid emit that Go links? | Go source + //line diagnostics; emitted Go assembly for trampolines |
✅ spike 2: 14/14 |
| What does a Go→Rust call cost? | 2.8 ns safe stack-switched trampoline vs 46.8 ns cgo — 16.5× faster, 0 allocs | ✅ spike 1 · G2 bench: fast path 3.37 ns ≤ 5 ns on the live bridge |
| Can consumers skip the toolchain? | Yes — generated Go + prebuilt artifact; a plain go run imports a Hybrid package |
✅ example 09 |
| Can a scheduler-safe checked language work at all? | Bounded blocking pool, two-tier budgets, race-clean under -race |
✅ spike 4: 100k-cell matrix |
| Ownership rules without visible lifetimes? | Tier-0 checker: 6 sendable classes, move/freeze, loans, fail-closed boundary | ✅ checker corpus 30/30 + differential loop |
| Scheduling with blocking Rust calls | resolved: pool + Go-scheduler fallback, budgets pinned | ✅ spike 4 |
One command, no Rust toolchain (the bridge staticlib ships prebuilt):
curl -fsSL https://raw.githubusercontent.com/limitlessprojects/Go-Hybrid/main/install.sh | shPrefer building from source? The pins are the contract (Go 1.26.9 / Rust 1.99.0):
git clone https://github.com/limitlessprojects/Go-Hybrid.git && cd Go-Hybrid
make examples # all ten target programs, byte-exact vs expected.txt
make test-quick # 255 compiler tests + checker corpus (26/26) + differential (9/9 + 11/11)
make bench # G2 call-overhead bench on the LIVE bridge
hyb build examples/01-hello/program.hy -o hello && ./hello
hyb build --package mypkg --out-dir out --binding-prefix example.com/mypkgThe ten examples are the acceptance suite: worker pools with backpressure, JSON transforms through serde_json, net/http servers, an LRU with generics, graph ownership moves, a Rust-crate digest service, and a Hybrid package consumed by plain Go — every one parses, checks, emits, builds and runs byte-exact in CI.
Windows note: bridge programs build and run on Windows today. The
Win64 trampolines (call_win64.s) landed and are fleet-proven: every
release's Windows leg links the staticlib through mingw cgo and runs the
full runtime suite natively — real crossings through the real trampolines
(PLAN row 17; the fleet crashes that shaped the ABI work — struct-by-value
args and stack alignment — are recorded there). hyb accepts both
staticlib flavors (libhyrt.a from mingw builds, hyrt.lib from msvc
builds). The one requirement: a mingw-w64 gcc for the cgo link.
A pinned-toolchain image (Go 1.26.9 + release hyb + the prebuilt runtime —
bridge programs included, no Rust needed at run time):
docker run --rm -v "$PWD:/work" -w /work ghcr.io/limitlessprojects/go-hybrid:latest hyb build ./program.hy -o /work/out && /work/outAlso usable as a CI container: — HYB_RUNTIME_DIR is wired. The image is
smoke-tested (pins + bridge-free + a serde_json bridge crossing) before it
is pushed; see .github/workflows/docker-publish.yml.
No new build system, no separate module culture — .hy files live beside
your .go files and transpile to checked-in, reviewable, gofmt-clean Go
(discussion #3,
design B). A complete working sample lives at
examples/gomod-integration/ — this is the
whole recipe:
# 1. vendor the runtime once (binding packages + prebuilt staticlib)
hyb vendor-runtime .
# 2. add two lines to your go.mod
# require hybrid.program v0.0.0
# replace hybrid.program => ./hybridrt
# 3. drop .hy files beside your .go files + one generate line in any Go file:
# //go:generate hyb generate .
go generate ./...
go build ./... && go test ./...The generated <name>.hy.go is plain Go: read it, diff it, review it.
Delete the .hy file and your project is a plain Go module again — the
pitch is literal. CI staleness gate: hyb generate --check . fails when a
.hy changed without regenerating, so untranspiled code can never silently
skip the checker.
- You need arbitrary existing Go code to run unmodified inside the checked
subset —
.hychecking covers Hybrid files, not.gofiles (that boundary is Go's usual story, honestly scoped in the spec). - You need every Rust crate on day one — the curated set grows per release.
- You need a 1.0 stability contract — the language, ABI and CLI will still change; pin versions and read the changelog.
- Your hot path can't tolerate Go's GC pauses — put that path in Rust and call it from Hybrid; don't put it in Hybrid-shaped Go.
Staying in Go is excellent for most code; a full Rust rewrite is right when you can afford it; cgo works today but leaves unsafe boundaries hand-audited and two build systems hand-run. Hybrid's bet is checked boundaries and one command.
MVP: DONE (G0 → G1 → G2 → G3 all passed/ratified, 2026-10-13 — gates record the claim-by-claim re-verification). Post-MVP queue, in order: runtime sanitizers/fuzzing on the Actions fleet · worker-tier bench · per-callee stack budgets · release engineering (v0.1.0 — this release) · community/feedback · packaging polish. Checkbox-level detail with dates and exit criteria: PLAN.md.
We're running a public feedback thread for exactly the questions this release should answer: What would make you trust — and adopt — a safety-checked Go superset? Short, blunt answers are the most useful kind; good advice gets merged into the roadmap with credit. Q&A, ideas, and show-and-tell are open under Discussions.
Before starting, ⭐ star the repository. It helps us grow and shows you're committed to contributing!
good first issue
issues are tagged. Docs, adversarial test corpora, diagnostic wording, and
example programs are all high-leverage right now. There is a $500 bounty
pool over the top 10 contributions each cycle: reproduced soundness bugs
and useful improvements alike, with severity tiers and a Hall of Fame —
the full rules are in BOUNTY.md. The Wildcard Track adds
another $500 per cycle for revolutionary, contrarian, high-risk ideas a
normal feature bounty would reject — no prototype required, breaking
changes and rewrites explicitly allowed, failures published as learnings
(and paid): ledger and solicitation calendar in MOONSHOT.md.
The project follows an
evidence-first protocol: hypotheses are pre-registered before measurement,
failures are reported plainly, and tests are never weakened to pass — see
AGENTS.md for how the repo works. Security reports start at
SECURITY.md; roles and credit live in
CONTRIBUTOR_RECOGNITION.md.
The All-Contributors bot keeps this table current. Ask it for credit with
@all-contributors please add @yourname for code (or bug, doc,
security, test) on your PR or issue — how each role is earned is in
CONTRIBUTOR_RECOGNITION.md.
Dual-licensed under MIT or Apache-2.0, at your option — the same formula as the Rust ecosystem. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you shall be dual-licensed as above, without any additional terms or conditions.