Pure-Go library and CLI for Fossil SCM repositories
See the code
Pure-Go library and CLI for Fossil repositories. Drop-in compatible with Fossil's .fossil SQLite format, with no CGo and no upstream fossil binary required.
The repository and module path are go-libfossil (
go get github.com/danmestas/go-libfossil), but the Go package is still imported aslibfossiland the CLI installs as thelibfossilcommand. Only the path moved; the package and binary names are unchanged.
GOOS=wasip1 GOARCH=wasm.Repo API directly in your Go service. No subprocess calls, no temp files.go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
The binary is named libfossil to avoid $PATH collisions with upstream fossil.
go get github.com/danmestas/go-libfossil
libfossil repo new my.fossil
libfossil -R my.fossil repo ci -m "first commit" hello.txt
libfossil -R my.fossil repo timeline
libfossil -R my.fossil repo ls
libfossil -R my.fossil repo annotate hello.txt
libfossil -R my.fossil repo verify
Full command list: libfossil --help. See docs/migration-from-fossil.md for a command-by-command comparison with upstream Fossil.
package main
import (
"log"
libfossil "github.com/danmestas/go-libfossil"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
func main() {
r, err := libfossil.Create("my.fossil", libfossil.CreateOpts{User: "admin"})
if err != nil {
log.Fatal(err)
}
defer r.Close()
rid, uuid, err := r.Commit(libfossil.CommitOpts{
Files: []libfossil.FileToCommit{{Name: "hello.txt", Content: []byte("hello")}},
Comment: "initial commit",
User: "admin",
})
if err != nil {
log.Fatal(err)
}
log.Printf("committed rid=%d uuid=%s", rid, uuid[:12])
entries, err := r.Timeline(libfossil.TimelineOpts{Limit: 10})
if err != nil {
log.Fatal(err)
}
for _, e := range entries {
log.Printf(" %s %s", e.UUID[:12], e.Comment)
}
}
Working example: examples/embed-repo-api/.
// Sync with a remote Fossil server.
result, err := r.Sync(ctx,
libfossil.NewHTTPTransport("http://host/repo"),
libfossil.SyncOpts{Push: true, Pull: true},
)
// Serve the sync protocol (e.g. for leaf agents, bridges, mirrors).
http.Handle("/", r.XferHandler())
The Transport interface is pluggable — swap HTTP for NATS, WebSocket, libp2p, or anything that delivers bytes round-trip.
cli/ exposes Kong command structs you can mount inside your own CLI:
import (
"github.com/alecthomas/kong"
"github.com/danmestas/go-libfossil/cli"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
type MyCLI struct {
cli.Globals
Repo cli.RepoCmd `cmd:"" help:"Fossil repo operations"`
// Add your own commands here.
}
func main() {
var c MyCLI
ctx := kong.Parse(&c)
ctx.FatalIfErrorf(ctx.Run(&c.Globals))
}
| Package | Purpose |
|---|---|
root (libfossil) | Repo handle, Transport, SyncObserver, CheckoutObserver |
cli/ | Embeddable Kong command structs for the repo subcommands |
cmd/libfossil/ | Standalone CLI binary |
db/ | SQLite abstraction with pluggable drivers |
db/driver/modernc | Pure-Go SQLite driver (default) |
db/driver/ncruces | wasm-capable SQLite driver |
observer/otel/ | Optional OpenTelemetry observer (separate submodule) |
dst/ | Deterministic simulation tests + BUGGIFY harness |
simio/ | Clock, Rand, Storage interfaces for deterministic testing |
testutil/ | Shared test helpers |
Deep dive: docs/architecture.md.
| Driver | Import | When to use |
|---|---|---|
modernc (default) | _ "github.com/danmestas/go-libfossil/db/driver/modernc" | Default for any server, CLI, or desktop use |
ncruces | _ "github.com/danmestas/go-libfossil/db/driver/ncruces" | wasm targets (GOOS=wasip1 or browser/OPFS) |
Library embedders select exactly one driver with a blank import at link time; importing both panics. The shipped cmd/libfossil CLI uses modernc by default; go build -tags test_ncruces ./cmd/libfossil selects ncruces. See docs/extension-points.md for the registration contract.
// Built-in, zero dependencies.
libfossil.NopSyncObserver() // silent
libfossil.StdoutSyncObserver() // human-readable stderr
// Optional OpenTelemetry (separate submodule — no OTel deps in core).
import "github.com/danmestas/go-libfossil/observer/otel"
obs := otel.NewSyncObserver()
Both SyncObserver and CheckoutObserver are small interfaces you can implement directly. Details: docs/extension-points.md.
libfossil compiles to a generic WASI Preview 1 module via the ncruces driver:
GOOS=wasip1 GOARCH=wasm go build -o libfossil.wasm ./examples/wasm/
See examples/wasm/ for a runnable demo and current runtime caveats (the non-js ncruces driver variant has a known locking-mode quirk under wasmtime).
make test — unit tests with the default modernc drivermake test-drivers — unit tests against both modernc and ncrucesmake test-otel — OTel submodule tests (runs with GOWORK=off)make test-all — everything, including the binary buildmake setup-hooks — install the pre-commit hook (~45s/commit)Test strategy — unit tests, dual-driver matrix, and deterministic simulation (DST) with BUGGIFY fault injection: docs/testing.md.
Full documentation: https://libfossil-docs.daniel-mestas.workers.dev.
Local preview: make docs-serve, then visit http://localhost:1313/.
Markdown sources: docs/site/content/.
| Doc | Audience |
|---|---|
| docs/architecture.md | Contributors learning the codebase |
| docs/testing.md | Contributors writing or debugging tests |
| docs/extension-points.md | Consumers adding observers or custom drivers |
| docs/migration-from-fossil.md | Users coming from upstream fossil |
| CONTRIBUTING.md | Anyone submitting a PR |
| CHANGELOG.md | Release notes |
See CONTRIBUTING.md.
This project stands on the work of others.
MIT — see LICENSE.
Go
99.6%
Pure-Go library and CLI for Fossil SCM repositories
See the code
Pure-Go library and CLI for Fossil repositories. Drop-in compatible with Fossil's .fossil SQLite format, with no CGo and no upstream fossil binary required.
The repository and module path are go-libfossil (
go get github.com/danmestas/go-libfossil), but the Go package is still imported aslibfossiland the CLI installs as thelibfossilcommand. Only the path moved; the package and binary names are unchanged.
GOOS=wasip1 GOARCH=wasm.Repo API directly in your Go service. No subprocess calls, no temp files.go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
The binary is named libfossil to avoid $PATH collisions with upstream fossil.
go get github.com/danmestas/go-libfossil
libfossil repo new my.fossil
libfossil -R my.fossil repo ci -m "first commit" hello.txt
libfossil -R my.fossil repo timeline
libfossil -R my.fossil repo ls
libfossil -R my.fossil repo annotate hello.txt
libfossil -R my.fossil repo verify
Full command list: libfossil --help. See docs/migration-from-fossil.md for a command-by-command comparison with upstream Fossil.
package main
import (
"log"
libfossil "github.com/danmestas/go-libfossil"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
func main() {
r, err := libfossil.Create("my.fossil", libfossil.CreateOpts{User: "admin"})
if err != nil {
log.Fatal(err)
}
defer r.Close()
rid, uuid, err := r.Commit(libfossil.CommitOpts{
Files: []libfossil.FileToCommit{{Name: "hello.txt", Content: []byte("hello")}},
Comment: "initial commit",
User: "admin",
})
if err != nil {
log.Fatal(err)
}
log.Printf("committed rid=%d uuid=%s", rid, uuid[:12])
entries, err := r.Timeline(libfossil.TimelineOpts{Limit: 10})
if err != nil {
log.Fatal(err)
}
for _, e := range entries {
log.Printf(" %s %s", e.UUID[:12], e.Comment)
}
}
Working example: examples/embed-repo-api/.
// Sync with a remote Fossil server.
result, err := r.Sync(ctx,
libfossil.NewHTTPTransport("http://host/repo"),
libfossil.SyncOpts{Push: true, Pull: true},
)
// Serve the sync protocol (e.g. for leaf agents, bridges, mirrors).
http.Handle("/", r.XferHandler())
The Transport interface is pluggable — swap HTTP for NATS, WebSocket, libp2p, or anything that delivers bytes round-trip.
cli/ exposes Kong command structs you can mount inside your own CLI:
import (
"github.com/alecthomas/kong"
"github.com/danmestas/go-libfossil/cli"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
type MyCLI struct {
cli.Globals
Repo cli.RepoCmd `cmd:"" help:"Fossil repo operations"`
// Add your own commands here.
}
func main() {
var c MyCLI
ctx := kong.Parse(&c)
ctx.FatalIfErrorf(ctx.Run(&c.Globals))
}
| Package | Purpose |
|---|---|
root (libfossil) | Repo handle, Transport, SyncObserver, CheckoutObserver |
cli/ | Embeddable Kong command structs for the repo subcommands |
cmd/libfossil/ | Standalone CLI binary |
db/ | SQLite abstraction with pluggable drivers |
db/driver/modernc | Pure-Go SQLite driver (default) |
db/driver/ncruces | wasm-capable SQLite driver |
observer/otel/ | Optional OpenTelemetry observer (separate submodule) |
dst/ | Deterministic simulation tests + BUGGIFY harness |
simio/ | Clock, Rand, Storage interfaces for deterministic testing |
testutil/ | Shared test helpers |
Deep dive: docs/architecture.md.
| Driver | Import | When to use |
|---|---|---|
modernc (default) | _ "github.com/danmestas/go-libfossil/db/driver/modernc" | Default for any server, CLI, or desktop use |
ncruces | _ "github.com/danmestas/go-libfossil/db/driver/ncruces" | wasm targets (GOOS=wasip1 or browser/OPFS) |
Library embedders select exactly one driver with a blank import at link time; importing both panics. The shipped cmd/libfossil CLI uses modernc by default; go build -tags test_ncruces ./cmd/libfossil selects ncruces. See docs/extension-points.md for the registration contract.
// Built-in, zero dependencies.
libfossil.NopSyncObserver() // silent
libfossil.StdoutSyncObserver() // human-readable stderr
// Optional OpenTelemetry (separate submodule — no OTel deps in core).
import "github.com/danmestas/go-libfossil/observer/otel"
obs := otel.NewSyncObserver()
Both SyncObserver and CheckoutObserver are small interfaces you can implement directly. Details: docs/extension-points.md.
libfossil compiles to a generic WASI Preview 1 module via the ncruces driver:
GOOS=wasip1 GOARCH=wasm go build -o libfossil.wasm ./examples/wasm/
See examples/wasm/ for a runnable demo and current runtime caveats (the non-js ncruces driver variant has a known locking-mode quirk under wasmtime).
make test — unit tests with the default modernc drivermake test-drivers — unit tests against both modernc and ncrucesmake test-otel — OTel submodule tests (runs with GOWORK=off)make test-all — everything, including the binary buildmake setup-hooks — install the pre-commit hook (~45s/commit)Test strategy — unit tests, dual-driver matrix, and deterministic simulation (DST) with BUGGIFY fault injection: docs/testing.md.
Full documentation: https://libfossil-docs.daniel-mestas.workers.dev.
Local preview: make docs-serve, then visit http://localhost:1313/.
Markdown sources: docs/site/content/.
| Doc | Audience |
|---|---|
| docs/architecture.md | Contributors learning the codebase |
| docs/testing.md | Contributors writing or debugging tests |
| docs/extension-points.md | Consumers adding observers or custom drivers |
| docs/migration-from-fossil.md | Users coming from upstream fossil |
| CONTRIBUTING.md | Anyone submitting a PR |
| CHANGELOG.md | Release notes |
See CONTRIBUTING.md.
This project stands on the work of others.
MIT — see LICENSE.
Go
99.6%