# go-libfossil Documentation (Full)
> Every documentation page concatenated in sidebar order. Curated overview: https://libfossil-docs.daniel-mestas.workers.dev/llms.txt
---
# Documentation
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/
go-libfossil reads, writes and syncs Fossil repositories in Go, without cgo. It ships as a Go module and as the `libfossil` command.
- **[Get started](/docs/get-started/)**: install, a first repository from the command line, the library from Go, and a first sync.
- **[Concepts](/docs/concepts/)**: artifacts, the derived tables, the sync protocol, sub-manifests, sparse cones, horizons and signing.
- **[Guides](/docs/guides/)**: production use, migrating from fossil, embedding the CLI, extension points and testing.
- **[Reference](/docs/reference/)**: the Go API, the command line, settings, and conformance with the drafts.
- **[Examples](/docs/examples/)**: runnable programs in the repository.
---
# Get started
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/get-started/
Install the `libfossil` command, make a first repository from the command line, embed the library in a Go program, and sync with another repository.
- [Install](/docs/get-started/install/): the command, the Go module, and the SQLite driver.
- [Quickstart: the CLI](/docs/get-started/quickstart/): create a repository, commit, and read it back with stock `fossil`.
- [Embed in Go](/docs/get-started/embed-in-go/): create, commit, open and read history from Go.
- [First sync](/docs/get-started/first-sync/): serve a repository, clone it, pull and push.
---
# Install
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/get-started/install/
go-libfossil is a Go module and a command. Neither needs cgo, a C toolchain or an installed `fossil`.
## The command
```sh
go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
libfossil --help
```
This needs the Go toolchain named in `go.mod` (Go 1.26 or later). The binary is statically linked and runs on Linux, macOS and Windows. Every command is listed in the [CLI reference](/docs/reference/cli/).
## The library
```sh
go get github.com/danmestas/go-libfossil@latest
```
The library talks to SQLite through `database/sql` and does not pick a driver for you. Blank-import exactly one of the two driver modules in your `main` package; importing both panics at start-up.
| Driver | Import | Use it for |
|---|---|---|
| modernc | `_ "github.com/danmestas/go-libfossil/db/driver/modernc"` | servers, command-line tools, desktop: SQLite translated to Go |
| ncruces | `_ "github.com/danmestas/go-libfossil/db/driver/ncruces"` | `GOOS=js` and `GOOS=wasip1` builds: SQLite itself as WebAssembly |
Each driver is its own module, so `go get` it too:
```sh
go get github.com/danmestas/go-libfossil/db/driver/modernc@latest
```
## WebAssembly
With the ncruces driver the module builds for `GOOS=js GOARCH=wasm` (a browser) and `GOOS=wasip1 GOARCH=wasm` (any WASI Preview 1 host). CI builds the module's packages for `js/wasm` on every change. The [wasm example](https://github.com/danmestas/go-libfossil/tree/main/examples/wasm) builds and runs a WASI module.
### TinyGo
The whole public API, the HTTP sync client and signing included, also builds with [TinyGo](https://tinygo.org) for the `wasm` target, which is what makes it small enough to ship with a page or an edge function:
```
tinygo build -target=wasm -no-debug -opt=z -stack-size=1MB -o libfossil.wasm ./examples/tinygo/
wasm-opt -Oz --detect-features --strip-debug --strip-producers libfossil.wasm -o libfossil.wasm
```
- **Size:** for [`examples/tinygo`](https://github.com/danmestas/go-libfossil/tree/main/examples/tinygo), about 1.3 MB gzipped as CI builds it, against about 4.1 MB from the standard toolchain. A program without sync is smaller.
- **Driver:** a TinyGo build imports no SQLite driver. The host registers a `database/sql` driver over its own SQLite; ncruces is for standard Go builds and modernc has no wasm build.
- **Stack:** `-stack-size=1MB`, because TinyGo's default goroutine stack is too small for the deeper paths.
- **Differences:** under TinyGo a sync redirect ends the request with an error instead of being followed, and DNS failures are not classified as transient.
CI builds `examples/tinygo` with TinyGo 0.43 on every change.
## Next
- [Quickstart: the CLI](/docs/get-started/quickstart/)
- [Embed in Go](/docs/get-started/embed-in-go/)
---
# Quickstart: the CLI
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/get-started/quickstart/
Create a repository, commit a file, and read the result with stock `fossil`. The `libfossil` command drives the same code as the library, and the file it writes is an ordinary Fossil repository.
## Create a repository and a checkout
```sh
libfossil repo new notes.fossil
mkdir work && cd work
libfossil -R ../notes.fossil repo open .
```
```text
created repository: notes.fossil
opened checkout in . (repo: /home/ana/notes.fossil)
empty repository -- no checkins yet
```
`repo open` writes a `.fslckout` file in the directory. Commands run inside the checkout find the repository through it, so `-R` is only needed to open it.
## Commit
```sh
echo '# notes' > README.md
libfossil repo add README.md
libfossil repo ci -m "first notes" --user ana
```
```text
ADDED README.md
checkin 542a963405 (rid=2)
```
The check-in name is the hash of the manifest, which includes the time, so yours differs. `--user` sets the name on the check-in; without it the OS user name is used.
## Read the history
```sh
libfossil repo timeline
```
```text
542a963405 2026-10-23 21:00 ana first notes
```
The repository is a Fossil repository, so the `fossil` binary reads it unchanged:
```sh
fossil timeline -R ../notes.fossil
```
```text
=== 2026-10-23 ===
21:00:14 [542a963405] first notes (user: ana tags: trunk)
+++ no more data (1) +++
```
## Next
- [Embed in Go](/docs/get-started/embed-in-go/): the same steps from a Go program.
- [First sync](/docs/get-started/first-sync/): serve the repository and clone it.
- [CLI reference](/docs/reference/cli/): every command and flag.
- [Migrating from fossil](/docs/guides/migrating-from-fossil/): how the commands map to fossil's.
---
# Embed in Go
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/get-started/embed-in-go/
The `libfossil` package does what the command does, as typed Go values instead of command output. This program creates a repository, commits a file and reads the history back.
## Set up
```sh
mkdir notes && cd notes
go mod init example.com/notes
go get github.com/danmestas/go-libfossil@latest github.com/danmestas/go-libfossil/db/driver/modernc@latest
```
The blank import of `db/driver/modernc` registers the SQLite driver. A program registers exactly one; see [Install](/docs/get-started/install/) for the choice.
## Create, commit, read
```go
package main
import (
"fmt"
"log"
"github.com/danmestas/go-libfossil"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
func main() {
r, err := libfossil.Create("notes.fossil", libfossil.CreateOpts{User: "ana"})
if err != nil {
log.Fatal(err)
}
defer r.Close()
rid, uuid, err := r.Commit(libfossil.CommitOpts{
Files: []libfossil.FileToCommit{{Name: "README.md", Content: []byte("# notes\n")}},
Comment: "first notes",
User: "ana",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("committed", uuid[:10], "rid", rid)
entries, err := r.Timeline(libfossil.TimelineOpts{Limit: 10})
if err != nil {
log.Fatal(err)
}
for _, e := range entries {
fmt.Println(e.UUID[:10], e.User, e.Comment)
}
files, err := r.ListFiles(rid)
if err != nil {
log.Fatal(err)
}
for _, f := range files {
fmt.Println(f.Name)
}
}
```
```sh
go run .
```
```text
committed ee68ff62c5 rid 2
ee68ff62c5 ana first notes
README.md
```
`Commit` returns the check-in's row id in the `blob` table and its full name. `CommitOpts.Files` lists file contents directly; no checkout or working directory is involved. To commit on top of an existing check-in, set `ParentID`: the files you pass replace the parent's entries of the same name and the rest of the parent's tree is carried forward, as `fossil commit` does.
The file is an ordinary Fossil repository: `fossil timeline -R notes.fossil` shows the same check-in.
## Open an existing repository
```go
r, err := libfossil.Open("notes.fossil")
if err != nil {
log.Fatal(err)
}
defer r.Close()
tip, err := r.BranchTip("trunk")
if err != nil {
log.Fatal(err)
}
files, err := r.ListFiles(tip)
```
`Open` fails if the file does not exist; `Create` fails if it does. Reads through one `*Repo` may run concurrently; writes serialize in SQLite. Close the handle once, when you are done with it. [Production patterns](/docs/guides/production/) covers error handling, contexts and handle lifetime.
## Next
- [First sync](/docs/get-started/first-sync/): clone, pull and push over HTTP.
- [SDK reference](/docs/reference/sdk/libfossil/api/): every exported type and function.
- [Examples](/docs/examples/): runnable programs in the repository.
---
# First sync
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/get-started/first-sync/
Two repositories exchange check-ins with Fossil's sync protocol over HTTP. `libfossil repo serve` is a sync server; `Clone`, `Repo.Sync` and `Repo.Pull` are the client. Either side can be stock `fossil`. [Sync](/docs/concepts/sync/) explains the protocol.
## Serve a repository
```sh
libfossil -R notes.fossil repo serve
```
```text
serving /home/ana/notes.fossil on http://127.0.0.1:8080 (Ctrl-C to stop)
```
`--addr` changes the bind address. The server answers sync requests only; it has no web interface.
An unauthenticated client gets the capabilities of the `nobody` user, which a new repository sets as `fossil new` does: clone and read, no check-in. To let a client push, give a user the check-in capability `i` and a password:
```sh
libfossil -R notes.fossil repo user add --cap=i bo
libfossil -R notes.fossil repo user passwd bo
```
Both commands print the user's generated password.
## Clone
From the command line, with either tool:
```sh
libfossil repo clone http://127.0.0.1:8080 copy.fossil
fossil clone http://127.0.0.1:8080 copy2.fossil
```
```text
Cloned into copy.fossil
Rounds: 2
Blobs: 2
Project-code: ec1581be7066e95dd3b9ee14b91ab3f258221ce4
```
`repo clone` also clones part of a repository: `--cone` by path and `--horizon` by age. See [Sparse cones](/docs/concepts/sparse-cones/) and [Horizons](/docs/concepts/horizons/).
## Clone, commit, push and pull from Go
```go
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/danmestas/go-libfossil"
_ "github.com/danmestas/go-libfossil/db/driver/modernc"
)
func main() {
ctx := context.Background()
url := "http://127.0.0.1:8080"
r, res, err := libfossil.Clone(ctx, "copy.fossil", libfossil.NewHTTPTransport(url), libfossil.CloneOpts{})
if err != nil {
log.Fatal(err)
}
defer r.Close()
fmt.Println("cloned", res.BlobsRecvd, "blobs in", res.Rounds, "rounds")
tip, err := r.BranchTip("trunk")
if err != nil {
log.Fatal(err)
}
if _, _, err := r.Commit(libfossil.CommitOpts{
Files: []libfossil.FileToCommit{{Name: "TODO.md", Content: []byte("- ship\n")}},
Comment: "add a todo",
User: "bo",
ParentID: tip,
}); err != nil {
log.Fatal(err)
}
pushed, err := r.Sync(ctx, libfossil.NewHTTPTransport(url), libfossil.SyncOpts{
Push: true, Pull: true, User: "bo", Password: os.Getenv("NOTES_PASSWORD"),
})
if err != nil {
log.Fatal(err)
}
fmt.Println("sent", pushed.FilesSent, "received", pushed.FilesRecvd)
pulled, err := r.Pull(ctx, url, libfossil.PullOpts{})
if err != nil {
log.Fatal(err)
}
fmt.Println("pull rounds", pulled.Rounds)
}
```
```sh
NOTES_PASSWORD=... go run .
```
```text
cloned 2 blobs in 2 rounds
sent 2 received 0
pull rounds 1
```
`Clone` creates the file and fails if it exists. `Sync` with `Push` and `Pull` runs one session in both directions until neither side has anything the other lacks; `Pull` is a pull-only shorthand that takes a URL. Without `User`, a session runs as `nobody`. Pass a context with a deadline in a service: a stalled peer otherwise holds the call open.
The commit made in the clone went to the origin:
```sh
libfossil -R notes.fossil repo timeline
```
```text
fb5af4c078 2026-10-23 21:02 bo add a todo
ee68ff62c5 2026-10-23 21:02 ana first notes
```
## Next
- [Sync](/docs/concepts/sync/): the cards and rounds behind these calls.
- [Production patterns](/docs/guides/production/): contexts, errors and telemetry for a long-running service.
- [Signing](/docs/concepts/signing/): signed check-ins and signed horizon seeds.
---
# Concepts
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/
How a Fossil repository is put together, and how go-libfossil implements it. Each page names the Internet-Draft in [`conformance/rfcs/`](https://github.com/danmestas/go-libfossil/tree/main/conformance/rfcs) that specifies the behaviour.
- [Architecture](/docs/concepts/architecture/): packages, drivers, observers and the simulator.
- [Artifacts](/docs/concepts/artifacts/): the text manifests that make up history, and how they are named.
- [Repository state](/docs/concepts/repository-state/): the tables derived from the artifacts.
- [Sync](/docs/concepts/sync/): the card protocol that clones, pulls and pushes.
- [Sub-manifests](/docs/concepts/sub-manifests/): check-ins written as trees instead of flat file lists.
- [Sparse cones](/docs/concepts/sparse-cones/): holding part of a repository by path.
- [Horizons](/docs/concepts/horizons/): holding part of a repository by age.
- [Signing](/docs/concepts/signing/): clear-signed check-ins and signed horizon seeds.
---
# Architecture
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/architecture/
<svg viewBox="0 0 640 260" role="img" aria-labelledby="arch-title arch-desc" preserveAspectRatio="xMidYMid meet" style="display:block;width:100%;height:auto;margin:0 auto 1.5rem;color:currentColor;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;max-width:720px">
<title id="arch-title">libfossil architecture</title>
<desc id="arch-desc">Callers (cli, library, wasm) invoke methods on the Repo handle. The Repo delegates to three pluggable axes: db driver, transport, observer. Repository state lives on disk in a .fossil SQLite file.</desc>
<style>
.a-rule { stroke: currentColor; stroke-width: 1; opacity: 0.4; }
.a-box { fill: none; stroke: currentColor; stroke-width: 1; opacity: 0.7; }
.a-head { font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase; opacity: 0.65; }
.a-item { font-size: 13px; }
.a-flow line { stroke: #c63a0f; stroke-width: 1.5; fill: none; }
.a-arrow { fill: #c63a0f; }
.a-flow-label { font-size: 10px; fill: #c63a0f; letter-spacing: 0.6px; text-transform: uppercase; }
</style>
<defs>
<marker id="arch-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path class="a-arrow" d="M0,0 L10,5 L0,10 Z"/>
</marker>
</defs>
<g class="a-rule">
<line x1="40" y1="38" x2="160" y2="38"/>
<line x1="240" y1="38" x2="400" y2="38"/>
<line x1="480" y1="38" x2="600" y2="38"/>
</g>
<g class="a-head" fill="currentColor">
<text x="100" y="28" text-anchor="middle">callers</text>
<text x="320" y="28" text-anchor="middle">core</text>
<text x="540" y="28" text-anchor="middle">plugins</text>
</g>
<g class="a-item" fill="currentColor">
<text x="100" y="76" text-anchor="middle">cli</text>
<text x="100" y="100" text-anchor="middle">library</text>
<text x="100" y="124" text-anchor="middle">wasm</text>
</g>
<rect class="a-box" x="240" y="60" width="160" height="100"/>
<g class="a-item" fill="currentColor">
<text x="320" y="88" text-anchor="middle">Open</text>
<text x="320" y="112" text-anchor="middle">Sync</text>
<text x="320" y="136" text-anchor="middle">Timeline</text>
</g>
<rect class="a-box" x="490" y="60" width="100" height="100"/>
<g class="a-item" fill="currentColor">
<text x="540" y="88" text-anchor="middle">db driver</text>
<text x="540" y="112" text-anchor="middle">transport</text>
<text x="540" y="136" text-anchor="middle">observer</text>
</g>
<rect class="a-box" x="240" y="200" width="160" height="40"/>
<g class="a-item" fill="currentColor">
<text x="320" y="225" text-anchor="middle">.fossil (SQLite)</text>
</g>
<g class="a-flow">
<line x1="160" y1="100" x2="234" y2="100" marker-end="url(#arch-arrow)"/>
<line x1="400" y1="88" x2="486" y2="88" marker-end="url(#arch-arrow)"/>
<line x1="490" y1="136" x2="404" y2="136" marker-end="url(#arch-arrow)"/>
<line x1="320" y1="160" x2="320" y2="196" marker-end="url(#arch-arrow)"/>
</g>
<g class="a-flow-label">
<text x="197" y="92" text-anchor="middle">calls</text>
<text x="443" y="80" text-anchor="middle">delegate</text>
<text x="447" y="154" text-anchor="middle">events</text>
<text x="334" y="183" text-anchor="start">persist</text>
</g>
</svg>
## Overview
libfossil is a pure-Go library and CLI that reads and writes Fossil SCM's
`.fossil` SQLite repositories. The public surface (package `libfossil`)
exposes `Repo`, `Create`, `Open`, `Clone`, checkout, and check-in
operations; internals live under `internal/`. SQLite access is mediated
by a pluggable driver layer in `db/`, with two shippable drivers
(`modernc`, `ncruces`) selected by blank import. Instrumentation is
pulled in by implementing the `SyncObserver` / `CheckoutObserver`
interfaces; an optional OTel adapter lives in its own submodule. A
deterministic simulator under `dst/` plus a `BUGGIFY` fault-injection
harness in `simio/` exercise concurrent repo operations under a seed.
## Module layout
The library is a Go workspace (`go.work`) of four modules: the root, the
two driver modules, and the OTel observer. (The documentation site under
`docs/site` has its own `go.mod` and is not in the workspace.) Layout:
- **Root package `libfossil`** — thin facade over `internal/repo`,
`internal/sync`, and `internal/checkout`. Main files: `fossil.go`
(Create, Open, Clone), `repo.go` (Repo handle + DB accessor),
`checkout.go`, `checkout_sparse.go` (cones and horizons),
`repo_checkout.go`, `repo_merge.go`, `repo_sync.go`, `repo_pull.go`,
`repo_sparse.go`, `repo_submanifest.go`, `repo_history.go`,
`repo_admin.go`, `repo_extras.go`, `required_content*.go`,
`horizon_*.go`, `signing.go`, `transport.go`, `observer.go`, `types.go`,
`errors.go`, `julian.go`.
- **`cli/`** — Kong command definitions. `repo.go` aggregates 43
subcommands (`new`, `clone`, `ci`, `co`, `timeline`, `diff`, `merge`,
`tag`, `branch`, `uv`, `stash`, `bisect`, `annotate`, `user`, `serve`,
`cone`, `submanifests`, etc.). Intended to be embedded by any `main` that
wants a fossil-shaped CLI.
- **`cmd/libfossil/`** — the shipped binary. `main.go` wires Kong and
dispatches to `cli`; `driver_modernc.go` and `driver_ncruces.go` select
the driver by build tag (`modernc` by default, `ncruces` under
`test_ncruces`).
- **`internal/`** — private implementation, grouped by concern:
- Storage layer: `blob`, `content`, `manifest`, `deck`, `delta`,
`hash`, `fsltype`, `repo` (schema + DB boot), `tag`, `leaf`,
`clearsign`.
- Sparse and horizon stores: `cone`, `horizon` (held set and seed).
- Working-tree operations: `checkout` (checkin, extract, update,
revert, fork, rename, status), `vfile`, `merge` (three-way, ancestor,
detect, resolve, strategies), `diff`, `annotate`, `undo`, `stash`,
`bisect`, `branch`, `path`.
- Sync / transport: `sync` (client, handler, clone, session,
ckin-lock, serve-http, table-sync, UV, sparse and horizon serving),
`xfer` (card codec).
- Housekeeping: `auth`, `shun`, `verify`, `search`, `uv`, `testdriver`.
- **`db/`** — SQLite abstraction (see below).
- **`db/driver/modernc`**, **`db/driver/ncruces`** — separate modules,
each registers exactly one `database/sql` driver.
- **`observer/otel/`** — separate module implementing the observer
interfaces against OpenTelemetry.
- **`dst/`** — deterministic simulator (`simulator.go`, `node.go`,
`network.go`, `peer_network.go`, `mock_fossil.go`, `invariants.go`,
`event.go`) with scenario-style tests.
- **`simio/`** — deterministic IO primitives: `SimClock`, seeded
`Rand`, in-memory storage, and the global `Buggify` switch.
- **`testutil/`** — shared test helpers for the rest of the tree.
## Storage model
A `.fossil` file is a SQLite database. All repository state — blobs,
manifests, tags, branches, unversioned files, tickets, wiki, config,
users — lives in that file. libfossil does not maintain any sidecar
state for the repo itself (a working tree has its own SQLite DB).
Content is stored **content-addressed** in the `blob` table, keyed by
either SHA1 or SHA3-256 names (the repository's hash policy picks which
names new content; see [Artifacts](/docs/concepts/artifacts/)). Every blob is
zlib-compressed with a 4-byte big-endian uncompressed-size prefix;
`internal/blob.Compress` and `Decompress` handle that framing. Blobs may
be stored as full content or as deltas against a parent; reconstruction
walks the chain and applies deltas via `internal/content.Expand`, with
cycle detection. `internal/content.Verify` rehashes expanded content
against the stored UUID.
**Structural artifacts** are themselves blobs whose text describes a
check-in (a manifest), a tag change, a wiki edit, a ticket change, an
attachment, a technote, a forum post, or a cluster. `internal/deck`
parses and marshals them and `internal/manifest` builds check-ins;
"crosslinking" (`internal/manifest/crosslink.go`) is the step that
projects an artifact's effects into derived tables (`mlink`, `plink`,
`event`, `tagxref`, etc.) so queries like timeline and checkout work
without re-parsing blobs. See [Repository state](/docs/concepts/repository-state/).
## Driver layer
`db/` is a thin wrapper over `database/sql`. See
[`db/doc.go`](https://github.com/danmestas/go-libfossil/blob/main/db/doc.go). A driver registers at `init` time via
`db.Register(DriverConfig{Name, BuildDSN})`; exactly one registration is
allowed (a second call panics). Library embedders blank-import exactly one
driver. `db.Open` / `db.OpenWith` look up the registered driver, run
`BuildDSN(path, pragmas)` to produce the DSN, and then call `sql.Open` with
that driver name. Both shipped drivers construct
`file:<path>?_pragma=k(v)&...` DSNs — differing only in the `database/sql`
driver name they register under (`"sqlite"` for modernc, `"sqlite3"` for
ncruces).
Shipped drivers:
- **`db/driver/modernc`** — default for `cmd/libfossil`. Blank-imports
`modernc.org/sqlite`, a pure-Go, CGo-free translation of SQLite with full
filesystem access.
- **`db/driver/ncruces`** — blank-imports `github.com/ncruces/go-sqlite3`,
which runs SQLite as WebAssembly. Has a `ncruces_js.go` variant for
`GOOS=js` / browser targets. Used for `GOOS=wasip1` builds and by
`go build -tags test_ncruces ./cmd/libfossil`.
## Sync protocol
`internal/sync` implements Fossil's sync-over-HTTP protocol as a client
and a stateless server, with the card codec in `internal/xfer`. See
[Sync](/docs/concepts/sync/) for the protocol and where each part lives.
## Observer model
The core keeps instrumentation as a non-goal; hooks are plain Go
interfaces on the public API. `SyncObserver` and `CheckoutObserver` in
[`observer.go`](https://github.com/danmestas/go-libfossil/blob/main/observer.go) define lifecycle events (session
start/end, per-round stats, extract/scan/commit phases). `NopSyncObserver`
/ `NopCheckoutObserver` are zero-cost defaults; `StdoutSyncObserver` /
`StdoutCheckoutObserver` log to stderr for quick debugging.
For OpenTelemetry, [`observer/otel`](https://github.com/danmestas/go-libfossil/tree/main/observer/otel/) is a separate Go
module so the core doesn't pull in the OTel SDK. Users import it
explicitly when they want traces, metrics, or structured logs.
See [Extension Points](/docs/guides/extension-points/) for the full observer
contract and a worked example of a custom observer.
## DST / simulation
`dst/` runs many Fossil nodes deterministically under a seed. A
`Simulator` (`dst/simulator.go`) owns a priority-queue event loop, a
`SimNetwork`, a `simio.SimClock`, and a set of `Node` actors. Scenarios
schedule clones, check-ins, merges, UV pushes, and partitions, and
tests assert invariants (`dst/invariants.go`, `crosslink_completeness_test.go`).
Fault injection has two forms. `simio.Buggify(p)` is a global
probability gate that returns `false` in production but flips `true`
with probability `p` once the simulator enables it; the blob and content
layers use it. The sync code instead asks a `BuggifyChecker` passed in
its options, at named sites such as `clone.emitCloneBatch.truncate` and
`handler.handleGimme.skip`; a nil checker injects nothing. `SeededBuggify`
in `dst` implements `BuggifyChecker` from a seeded random source.
See [Testing](/docs/guides/testing/) for running the DST matrix, seed sweeps,
and the driver test matrix.
---
# Artifacts
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/artifacts/
Everything a Fossil repository records is an **artifact**: a run of bytes, named by its own hash, that is never changed once written. File contents are artifacts. So are check-ins, tags, wiki pages and tickets, which are written as text **cards**. The format is `draft-fossil-artifact-format-00`.
## Names
An artifact's name is the hash of its exact stored bytes, with nothing added or stripped (§3.1). A 40-digit name is SHA-1; a 64-digit name is SHA3-256. The length alone tells which (§3.2). A signed artifact's name covers its signature wrapper too, so signing a check-in changes its name.
The repository's **hash policy** decides which algorithm names new content (§7.1):
| Policy | Names new content with |
|---|---|
| `sha1`, `auto` | SHA-1 |
| `sha3`, `sha3-only`, `shun-sha1` | SHA3-256 |
A repository with no policy set uses `sha3` unless it holds SHA-1 names and no SHA3 ones, in which case it uses `auto` (§7.2). A new repository is `sha3`. Names already assigned never change (§7.6). `Repo.SetHashPolicy(name)` sets the policy as `fossil hash-policy` does.
## Structural artifacts and cards
A structural artifact is lines of cards: a capital letter, then space-separated arguments, with the cards in sorted order and a `Z` card last (§4). There are eight types, and each allows a fixed set of cards (§5.1, §5.2):
| Type | External name | Allowed cards |
|---|---|---|
| MANIFEST | `checkin` | B C D F N P Q R T U Z |
| CLUSTER | `cluster` | M Z |
| CONTROL | `tag` | D T U Z |
| WIKI | `wiki` | C D L N P U W Z |
| TICKET | `ticket` | D J K U Z |
| ATTACHMENT | `attachment` | A C D N U Z |
| EVENT | `technote` | C D E N P T U W Z |
| FORUM | `forumpost` | D G H I N P U W Z |
Any other byte string is plain content, such as a file's bytes. A parser rejects a structural artifact with a card its type does not allow, or without one its type requires.
[Sub-manifests](/docs/concepts/sub-manifests/) add an `S` card and a ninth type.
## A check-in manifest
This is a check-in made with `libfossil repo ci`:
```
C unsigned
D 2026-10-23T20:45:21.324
F docs/x.md a09fd4d0069e85b78c5234233ffb67179d30e19c2ec94629d224257a920c1234
F src/a.c 7eae391285a140af77b34475a35c4790095acb1f0f5e6ec7e10e962b2405de07
F src/vendor/v.c bedef797cd3184c3c7e620c5c231bbdd523f52ab19ca6301d037c7f2a3f99780
P 2afc4615dadbd7743716f8037223578d7d07a79ebc2cbfd5ba1b6028f133c7f2
R 43fe2394e6714e382e2f6563c13cf020
U dmestas
Z 56b668a3573378eb3e2387902909b385
```
- `C`: the check-in comment.
- `D`: the date, UTC.
- `F`: one per file: path and content hash, then optional permissions and an old name for a rename.
- `P`: the parent check-ins. The first is the primary parent; the rest are merge parents.
- `R`: an MD5 over every file's name, size and content (§6.3). A commit reads its manifest back and checks it. Over a sparse store there is no `R` card.
- `U`: the user.
- `Z`: the MD5 of every byte before it (§6.2).
The first check-in on a branch also carries `T` cards, such as `T *branch * trunk` and `T *sym-trunk *`. A **delta manifest** carries a `B` card naming a baseline manifest, and its `F` cards record only the differences from it (§8).
The name of this check-in is the SHA3-256 of exactly these bytes: `libfossil repo hash --sha3` over the output of `repo cat` prints `7507cc8c3e...`, the name the timeline shows.
## Deltas
Content is stored in the `blob` table, zlib-compressed behind a 4-byte size prefix. A blob can also be stored as a **delta** against another blob, with the pair recorded in the `delta` table (`rid`, `srcid`). Reading it applies the chain of deltas back to a full blob, and the result must hash to the blob's name.
A delta is a header with the target length, a run of copy and insert segments, and a trailer with a checksum of the result (`draft-fossil-delta-format-00` §3). Integers are written in base 64. A delta does not name its source; the storage layer records that (§1).
As in fossil, deltas run backwards: a new version is stored whole and its predecessor is rewritten as a delta against it, so the newest version of a file is always one read away.
## Where the code is
- `internal/deck`: parse and marshal cards, the `Z` card, signature-wrapper stripping.
- `internal/manifest`: build check-ins, compute the `R` card, crosslink.
- `internal/delta`: create and apply deltas (`Create`, `Apply`).
- `internal/hash`: SHA-1 and SHA3-256 names and the hash policy.
- `internal/blob` and `internal/content`: compressed storage, delta chains, verification.
---
# Repository state
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/repository-state/
[Artifacts](/docs/concepts/artifacts/) are the only facts a repository records. Everything else, such as which check-in is the tip of trunk, which branch a check-in is on, or which leaves are open, follows from them. `draft-fossil-repo-state-00` specifies that derivation, so two implementations reading the same artifacts reach the same answers. The one exception is the current trunk, which also reads the repository's `main-branch` setting (§9).
## The tables
A `.fossil` file stores the artifacts in `blob` and `delta`, and keeps the derived state in tables beside them, so a query does not re-parse every artifact.
| Table | Holds |
|---|---|
| `blob` | Every artifact, compressed, by `rid` and name (`uuid`). A row with no content is a phantom. |
| `delta` | Which blobs are stored as deltas, and against what. |
| `phantom` | Names the repository knows of but does not hold yet. |
| `event` | One row per check-in, tag, wiki edit, ticket change and so on: the timeline. |
| `plink` | Parent links between check-ins, with which parent is primary (§3). |
| `mlink` | Which file changed in which check-in, and from which earlier version. |
| `filename` | The file names `mlink` refers to. |
| `tag`, `tagxref` | Tag names, and each tag's effect on each check-in: cancel, singleton or propagating (§5). |
| `leaf` | Check-ins with no child on their own branch (§7). |
| `orphan` | Delta manifests whose baseline is absent. |
`blob` and `delta` are the source. The others are derived.
## Crosslinking
**Crosslinking** reads one artifact and writes its effects into the derived tables (§4). A check-in adds its `plink` and `mlink` rows and its `event` row. Its `T` cards, or a control artifact's, set `tagxref` rows and propagate along primary children until a cancel or another value blocks them (§5.4). Leaves are rechecked as parents gain children and as tags move (§7.6).
Artifacts can arrive in any order. Sync, clone, a commit and a rebuild all crosslink, and an artifact whose parent has not arrived yet is linked again when it does.
Branches are not stored as such. A check-in's branch is the value of its `branch` tag, inherited from its primary parent unless a tag on it says otherwise (§6). Name resolution (§8) turns a branch name, tag or `trunk` into one check-in: `Repo.ResolveVersion(name)`. `Repo.CurrentTrunk()` returns the tip of the main branch (§9).
## Rebuild gives the same rows
Because the derived tables are a function of the artifacts, they can be thrown away and computed again. go-libfossil's rebuild (`verify.Rebuild`, internal) empties the crosslinked tables and runs the same crosslink sweep a clone runs, so derived state has one owner. The tables it refills are `event`, `plink`, `leaf`, `mlink`, `tagxref`, `forumpost`, `attachment`, `backlink`, `cherrypick` and `orphan`, plus the sync bookkeeping tables `unclustered` and `unsent`.
The conformance suite checks this against fossil itself:
- Each scripted case in `conformance/repostate_*_test.go` loads a sequence of artifacts into go-libfossil (one sweep, one artifact at a time, and through rebuild) and into fossil(1). The rows must equal the expectation written from the draft, and fossil's rows must equal it too: its per-artifact crosslink for a crosslink case, `fossil rebuild` on a copy for a rebuild case. The compared tables are `plink`, `tagxref`, `event`, `phantom`, `leaf`, `orphan` and `mlink`.
- `TestRepoStateCorpus` takes real repositories (named in `CONFORMANCE_REPOS`) and derives their tables three ways: `fossil rebuild` on one copy, as the reference; go-libfossil's rebuild on a second; a crosslink sweep over emptied tables on a third. It compares `event`, `leaf`, `mlink`, `phantom`, `plink` and `tagxref` column by column. It runs only when fossil(1) is present.
Where fossil departs from the draft text, the case records it and names the draft change proposed. The requirements are listed in `conformance/requirements/repostate.tsv`.
## Where the code is
- `internal/manifest`: crosslinking (`crosslink.go`), re-derivation (`rederive.go`), the timeline.
- `internal/tag`: tag application and propagation.
- `internal/leaf`: the leaf table.
- `internal/verify`: integrity checks and rebuild.
- `internal/repo`: the schema and the `main-branch` setting.
---
# Sync
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/sync/
Two repositories exchange artifacts with Fossil's sync protocol: text cards carried in HTTP POST bodies, one request and one reply per round. go-libfossil implements both ends, and talks to stock fossil, zit and other go-libfossil peers. The governing text is `draft-fossil-sync-protocol-00`.
## Messages and cards
A message is a list of cards, one per line: a card name, then space-separated arguments, and for content cards a byte payload after the line (§5). Unknown pragmas are ignored, so a peer can add new ones without breaking old ones (§3.5).
The client POSTs each request to the repository URL (§4). The body is a 4-byte big-endian length followed by a zlib stream (§4.1). A clone reply may be sent uncompressed, because its `cfile` payloads are already compressed.
The cards that move artifacts:
| Card | Meaning | Draft |
|---|---|---|
| `igot HASH` | I hold this artifact. `igot HASH 1` marks it private. | §8.6 |
| `gimme HASH` | Send me this artifact. | §8.6 |
| `file HASH SIZE` | The artifact's bytes, or a delta against another artifact (`file HASH DELTASRC SIZE`). Used by push and pull. | §7.1 |
| `cfile HASH USIZE CSIZE` | The artifact as the sender stores it, compressed, sent verbatim. Used by clone. | §7.2 |
| `push` / `pull` | The operation, with the server and project codes. | §3.2 |
| `clone 3 SEQNO` / `clone_seqno N` | The clone loop's position. | §8.2 |
| `login USER NONCE SIGNATURE` | Authentication. | §6.1 |
| `pragma NAME ...` | Version negotiation and extensions. | §9 |
| `error` / `message` | Errors and notices. | §10 |
Unversioned files travel as `uvigot`, `uvgimme` and `uvfile` (§7.3, §8.5.1). Configuration travels as `reqconfig` and `config` (§9.3).
## Rounds
A session is a loop of rounds. Each round the client says what it holds (`igot`) and what it wants (`gimme`), and sends the content the server asked for in the last reply. The server answers in kind. A `gimme` is never sent for a shunned artifact or one the peer has said it lacks (§8.8).
The client decides when to stop. It issues another round only while the last round made progress: it stored content and still has phantoms (artifacts it knows by name but does not hold), it queued content to send, or one of the unversioned-file or clone conditions holds (§3.7). Phantoms alone do not keep the loop running. The server sends no completion card.
## Clone, pull, push
- **Clone** starts with `clone 3 1`. The server sends its stored blobs as `cfile` cards in batches and a `clone_seqno` saying where to continue; zero ends the transfer and one cleanup round follows (§8.1 to §8.4). Artifacts the rounds leave missing stay phantoms, as with fossil's clone, unless `CloneOpts.PullPhantoms` is set.
- **Pull** sends `pull` each round and receives what it lacks.
- **Push** sends `push` each round and answers the server's `gimme` cards with `file` cards.
- **Sync** sends both.
After artifacts arrive they are [crosslinked](/docs/concepts/repository-state/), so branches, tags and leaves follow from the artifacts each side holds, not from anything sent on the wire (§8.6.1).
## Login
A named user signs each request (§6). `NONCE` is the SHA-1 of the request body after the login line. The shared secret is `SHA1(project-code "/" login "/" password)`, and `SIGNATURE` is `SHA1(NONCE || shared-secret)`. The first clone round carries no login. A request with no login runs as `nobody`. Once the server announces a version that reads it, the login moves to the `x-f-l-c` cookie (§6.5).
The server checks the user's capabilities from its `user` table (§6.6). In a new repository `nobody` may clone and pull but not push; grant more with `Repo.SetCaps`.
## The server is stateless
Each request is handled on its own (§8.9). The server keeps no session between rounds, so any number of clients can sync against one repository, and a server can sit behind any HTTP stack.
```go
repo, err := libfossil.Open("repo.fossil")
if err != nil {
log.Fatal(err)
}
defer repo.Close()
mux := http.NewServeMux()
mux.HandleFunc("/", repo.XferHandler())
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {})
log.Fatal(http.ListenAndServe(":8080", mux))
```
- `Repo.XferHandler()` returns an `http.HandlerFunc` that decodes a request, handles it and encodes the reply. A non-POST request gets a plain page.
- `Repo.ServeHTTP(ctx, addr)` runs a server on `addr` until `ctx` is cancelled. `libfossil repo serve --addr 127.0.0.1:8080` does the same from the command line.
- `Repo.HandleSync(ctx, payload)` and `HandleSyncWithOpts` take and return raw message bytes, for an embedder with its own transport. Over HTTP, pass the `x-f-l-c` cookie in `HandleOpts.LoginCookie` and the client address in `HandleOpts.RemoteAddr`; `XferHandler` and `ServeHTTP` fill both themselves.
## The client
```go
t := libfossil.NewHTTPTransport("https://example.com/repo")
repo, res, err := libfossil.Clone(ctx, "repo.fossil", t, libfossil.CloneOpts{
User: "alice", Password: "secret",
})
sr, err := repo.Sync(ctx, t, libfossil.SyncOpts{
Push: true, Pull: true, User: "alice", Password: "secret",
})
```
`Transport` is one method, `RoundTrip(ctx, payload) ([]byte, error)`, so any byte pipe works. `NewHTTPTransport` takes `WithHTTPClient` for a custom `http.Client`. `Repo.Pull(ctx, url, PullOpts{})` is a pull-only shortcut over HTTP.
`SyncOpts` also turns on unversioned files (`UV`), private artifacts (`Private`, §7.5), fossil's `--share-links` (`ShareLinks`, §9.5) and go-libfossil's own table sync (`XTableSync`). `SyncResult` reports rounds, files and bytes each way, and errors.
The `libfossil` binary clones (`repo clone`) and serves (`repo serve`). Pull, push and sync are library calls.
## Check-in lock
A client that is about to commit can ask the server to hold the parent with `pragma ci-lock` (§9.4). The server records a `ci-lock-<parent hash>` row in its `config` table and reports a conflicting holder with `ci-lock-fail`. A lock goes stale after the repository's `lock-timeout` setting, 60 seconds when unset (`DefaultCkinLockTimeout`). Fossil uses the same row, so a repository served by both shares one lock table.
## Shunned artifacts
A shunned artifact is never requested, and one that arrives is dropped rather than stored. The shun list itself can travel as the `shun` configuration group (§9.3).
## Extensions
Pragmas carry the extensions. Each is ignored by a peer that does not know it.
- [Sparse cones](/docs/concepts/sparse-cones/): `pragma cone`, answered by `cone-served` (`draft-fossil-sparse-cone-00` §6).
- [Horizons](/docs/concepts/horizons/): `horizon-served`, the seed and the cursor (`draft-fossil-horizon-00` §6).
- [Sub-manifests](/docs/concepts/sub-manifests/): `send-submanifests` and `avoid-submanifests` (`draft-fossil-submanifests-00` §7.2).
## Where the code is
- **Client** (`internal/sync/client.go`, `clone.go`, `session.go`): drives the rounds. Supports clone, pull, push and sync, plus unversioned files and config table sync (`client_tablesync.go`).
- **Server** (`internal/sync/handler.go`, `serve_http.go`, `handler_uv.go`, `handler_tablesync.go`): one request in, one reply out.
- **Cards** (`internal/xfer`): encoding and decoding of messages and cards.
- **Check-in lock** (`internal/sync/ckin_lock.go`).
- **Table sync deletes** (`internal/sync/xdelete.go`): an `xdelete` card removes a synced table row, or leaves a tombstone where the row is absent.
- **Public entry points**: `Clone` in `fossil.go`; `Repo.Sync`, `HandleSync`, `XferHandler` and `ServeHTTP` in `repo_sync.go`; `Repo.Pull` in `repo_pull.go`; `NewHTTPTransport` in `transport.go`.
---
# Sub-manifests
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/sub-manifests/
A check-in manifest has one `F` card per file in the tree, not per changed file. Its size grows with the width of the tree, and every check-in pays it. Sub-manifests split the file list into a tree of smaller artifacts, so a typical check-in rewrites the root manifest and one leaf. The format is `draft-fossil-submanifests-00`.
Two implementations exist: zit writes, reads and serves sub-manifests, and go-libfossil writes and reads them. The two interoperate. Fossil does not implement the draft (§1.3).
## The tree
A **sub-manifest** carries a contiguous slice of a check-in's sorted file list: `F` cards in a leaf, or `S` cards that point to lower sub-manifests in an interior node. A manifest whose files are given by `S` cards is a **tree manifest**. Walking the tree in order gives exactly the file list a flat manifest would carry (§5.1).
```
S src/a.c 5d0c...
```
An `S` card names the first file of the slice and the sub-manifest that holds it (§3.6). Sub-manifests are a ninth artifact type, `submanifest` (§4.1).
Where the boundaries fall depends only on file names. A name starts a new leaf when the SHA3-256 of the name has at least `k` leading zero bits (§6.1). Editing a file changes one leaf. Adding or removing a name can change a few until the boundaries line up again (§6.5). `k` is never written into an artifact, and readers do not need it.
## Settings
Three repository settings control writing. They travel by configuration exchange: a clone asks for them in its cleanup round and adopts them, and a pull does not (§6.3).
| Setting | Meaning | Default |
|---|---|---|
| `enable-submanifests` | Write new check-ins as trees (§8.1). | off |
| `submanifest-k` | The partition parameter, 1 to 12 (§6.3). | unpinned |
| `submanifest-auto-retune` | Let a commit re-pin `k` when it drifts (§6.4). | off |
When emission is first enabled with no pinned `k`, one is selected by the cost in §6.3 over the file list of the main branch's tip (the newest check-in when no check-in is on the main branch), then refined by replaying the last 200 check-ins. A tree with too few files for any `k` to split has no selection, and enabling fails; give `--k` explicitly. A pinned `k` outside 1 to 12 makes commits fall back to flat manifests with a warning.
A re-tune is forward only. The next commit shares only the sub-manifests whose bytes are the same under both values. With `submanifest-auto-retune` on, a commit re-pins `k` when the best candidate costs more than 15% less than the pinned one, zit's margin. With it off, the drift is only logged.
## Command line
```
$ libfossil -R repo.fossil repo submanifests status
enable-submanifests: off
submanifest-k: (unpinned)
submanifest-auto-retune: off
trees in repository: no
$ libfossil -R repo.fossil repo submanifests enable --k 4
$ libfossil -R repo.fossil repo submanifests retune --k 5
$ libfossil -R repo.fossil repo submanifests disable
```
- `enable [--k N]`: write new check-ins as trees, pinning `k` (selected when `--k` is absent). It prints a warning that fossil peers will be refused the trees.
- `retune --k N`: re-pin `k` for later commits.
- `disable`: write flat manifests again. Existing trees stay.
- `status`: show the three settings and whether the repository holds any tree.
The library calls are `Repo.EnableSubmanifests(k)` (0 selects; it returns the pinned `k` and the warning), `Repo.RetuneSubmanifests(k)` and `Repo.DisableSubmanifests()`.
## Sync
A peer that reads sub-manifests says so with `pragma send-submanifests` in every request and reply (§7.2). go-libfossil always sends it, whatever its settings. A peer that has not sent it is refused every sub-manifest and every tree manifest, with an explicit error. Nothing is converted or downgraded. Every fossil release is such a peer, so a repository with trees serves fossil only the history before the first tree.
A server whose `enable-submanifests` is off also sends `pragma avoid-submanifests`. It binds only commits made during that sync session. go-libfossil commits outside a session and pushes afterwards, so the pragma never binds its commits: whether a commit writes a tree is decided by the local `enable-submanifests` alone. The pragma does not stop a server storing a tree pushed to it.
## Things to know before enabling
- **It is a flag day.** Every reader of the repository must understand sub-manifests before any writer emits one (§8). A repository that a fossil peer serves must not enable them.
- **Trees cannot be retired.** Disabling stops new trees; artifact names are immutable, so the ones written stay, and fossil peers are still refused them.
- **Sparse stores hold every tree node.** A [sparse store](/docs/concepts/sparse-cones/) keeps all sub-manifest nodes, so history stays readable without the file content.
## Where the code is
- `internal/manifest`: tree construction (`treebuild.go`), writing and settings (`submanifest_write.go`), reading (`tree.go`).
- `internal/sync/submanifest.go`: the capability gate, both pragmas, and configuration exchange of the settings.
- `repo_submanifest.go` and `cli/repo_submanifests.go`: the public API and command.
---
# Sparse cones
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/sparse-cones/
A repository does not have to hold everything. A **cone** limits it by path. A [horizon](/docs/concepts/horizons/) limits it by age, and is carried as a member of a cone. Both leave the history intact, and the blobs they skip can be fetched later.
Cones follow `draft-fossil-sparse-cone-00`. They are implemented in step with zit.
## Cones
A cone is a set of repository paths. Each member is a directory subtree or a single file, and each is either an include or an exclude. Members are literal prefixes, not patterns (§3.4).
The longest member that covers a path decides it. An exclude carves a part out of an include, and a deeper include re-includes part of an exclude (§3.3):
```
include src
exclude src/vendor
include src/vendor/keep
```
`src/a.c` is covered. `src/vendor/v.c` is not. `src/vendor/keep/k.c` is covered again.
A cone must have at least one include, at most 255 members, and no exclude that no include covers. Order does not matter; members are sorted and reduced to the smallest set with the same coverage (§3.2).
### Checkout cones and store cones
A **checkout cone** limits the working directory (§4). The repository still holds every file. A sparse checkout writes, scans and tracks only the covered files. A commit carries the uncovered files from its parent unchanged, so it is the same check-in a dense checkout would make. Adding, removing, renaming or reverting an uncovered path fails with `ErrOutsideCone`.
A **store cone** limits the repository itself (§5). Blobs outside the cone are not fetched, and can be dropped by compaction. A checkout opens over a sparse store only if its own cone stays inside the store's.
Manifests, [sub-manifest](/docs/concepts/sub-manifests/) nodes and control artifacts are always held, so the whole history stays readable. Only file content is elided.
### Elided is not damaged
An artifact the store lacks is classified one of three ways (§5.2):
- **transit**: not here yet, and sync will ask for it.
- **shunned**: deliberately refused.
- **elided**: the cone says the store need not hold it.
Only elided is by design. Sync never requests an elided artifact, whether the store is the client or the server, and `verify` reports a store that is complete within its cone as OK. Elision is computed from the cone and never stored, so changing the cone reclassifies. Losing the cone, or one this version cannot read, turns every elided artifact back into a transit one and the store heals toward dense.
## Library usage
### Build a cone
```go
cone, err := libfossil.NewCone(
[]string{"src", "docs"}, // include
[]string{"src/vendor"}, // exclude
)
if err != nil {
log.Fatal(err)
}
fmt.Println(cone.Covers("src/main.go")) // true
covered, member := cone.Decide("src/vendor/x.c") // false, "src/vendor"
```
A `Cone` is immutable. `With`, `Without` and `WithHorizon` return new ones. `Include`, `Exclude`, `Digest`, `String` and `Horizon` read it.
### Sparse checkout
```go
repo, err := libfossil.Open("repo.fossil")
if err != nil {
log.Fatal(err)
}
defer repo.Close()
co, err := repo.CreateCheckout("work", libfossil.CheckoutCreateOpts{Cone: cone})
if err != nil {
log.Fatal(err)
}
defer co.Close()
// Widen, narrow, or pass nil to make the checkout dense.
change, err := co.SetCone(wider)
if err != nil {
log.Fatal(err)
}
fmt.Println(change.Materialized, change.Dematerialized)
```
`SetCone` writes the files the new cone adds and removes the ones it drops from the working directory. The repository keeps them. It refuses, changing nothing, when a file leaving the cone has local changes or a file entering it would overwrite an untracked one. A cone that carries a horizon fails with `ErrHorizonCheckout`.
Over a sparse store, widening needs content the store may not hold. `SetConeContext` takes a `RequiredContentOpts{Peer: transport}` and fetches it. With no peer the widening is refused and nothing changes.
### Clone into a sparse store
```go
t := libfossil.NewHTTPTransport("https://example.com/repo")
repo, res, err := libfossil.Clone(ctx, "repo.fossil", t, libfossil.CloneOpts{
StoreCone: cone,
})
if err != nil {
log.Fatal(err)
}
defer repo.Close()
fmt.Println(res.Elided, res.ConeServed)
```
The result counts:
- `Elided`: artifacts left absent under the cone.
- `ConeServed`: replies where the server acknowledged applying the cone (`pragma cone-served`, §6.3). The other rounds were served densely and filtered locally.
Both are zero for a dense clone. `SyncResult` has the same fields. A server that will not serve a sparse clone refuses it. A cone with a horizon clones a horizon store; see [Horizons](/docs/concepts/horizons/).
### Set, widen and drop on an existing store
```go
// Set or replace, without a peer. Narrowing deletes nothing.
err = repo.SetStoreCone(next)
// Read it.
cur, err := repo.StoreCone()
// Widen, and fetch what that newly covers.
sr, err := repo.SetStoreConeContext(ctx, wider, libfossil.RequiredContentOpts{
Peer: t,
})
// Drop the cone. Fetch everything it elided.
sr, err = repo.SetStoreConeContext(ctx, nil, libfossil.RequiredContentOpts{Peer: t})
// Drop held blobs the cone elides. See Limits.
n, err := repo.CompactStore(ctx)
```
`SetStoreCone` moves no content. Widening makes the newly covered elided artifacts wanted again, and the next pull fetches them. `SetStoreConeContext` does the pull itself through an ordinary cone-scoped sync. With artifacts to fetch and no `Peer`, it refuses, names the count, and leaves the cone unchanged. If the transfer fails after the cone is replaced, the wider policy stays and the next pull heals it. While a store cone is set, a commit carries no R card. `CompactStore` on a dense store fails with `ErrNoStoreCone`.
## Command line
### Open a sparse checkout
```
libfossil -R repo.fossil repo open [DIR] --cone src --cone docs --cone-not src/vendor
```
- `--cone=CONE,...`: make a sparse checkout; materialize and track only this path's subtree (repeatable).
- `--cone-not=CONE-NOT,...`: exclude this path's subtree from an enclosing `--cone` (repeatable).
### Edit the checkout cone
All of these take `-d, --dir` for the checkout directory (default `.`).
```
libfossil repo cone show
libfossil repo cone add src/extra
libfossil repo cone add --not src/gen
libfossil repo cone remove src/extra
libfossil repo cone set src docs --not src/vendor
libfossil repo cone dense
libfossil repo cone test src/a.c src/vendor/v.c
```
- `show`: list the cone's members ("dense" when there is none).
- `add <paths>`: widen the cone, or with `--not` carve paths out of it.
- `remove <paths>`: remove members of either polarity.
- `set <paths>`: replace the cone. `--not` takes the exclusions.
- `dense`: drop the cone and materialize every file.
- `test <paths>`: classify paths against the cone and name the deciding member. It exits non-zero when any path is elided, so it works as a predicate. `-q` prints nothing and reports through the status only.
`add`, `remove`, `set` and `dense` can need content the store lacks. They take `--remote` (default: the saved last-sync-url), `--sync-user`, `--sync-pass` (never saved), `--sync-private` and `--timeout` (default 10m; 0 disables it).
### Clone a sparse store
```
libfossil repo clone URL repo.fossil --cone src --cone-not src/vendor
```
- `--cone=CONE,...`: clone a sparse store: fetch only this path's subtree (repeatable).
- `--cone-not=CONE-NOT,...`: carve this path out of a `--cone` (repeatable).
`--horizon`, `--leaves`, `--structural` and `--seed-key` combine with these; see [Horizons](/docs/concepts/horizons/).
### Change the store cone
```
libfossil -R repo.fossil repo cone store # show it
libfossil -R repo.fossil repo cone store src docs --not src/vendor
libfossil -R repo.fossil repo cone store --dense
libfossil -R repo.fossil repo cone compact
```
- With no paths, `store` shows the store cone. With paths, it replaces it and fetches what the widening covers. `--not` takes the exclusions.
- `--dense`: drop the store cone, fetching everything it elided.
- `compact`: drop held blobs the store cone elides (irreversible locally).
`store` takes the same `--remote`, `--sync-user`, `--sync-pass`, `--sync-private` and `--timeout` flags as above. Its `--horizon`, `--leaves`, `--structural` and `--no-horizon` flags are described under [Horizons](/docs/concepts/horizons/).
## Interoperability
**zit.** The cone format matches zit's byte for byte, so a cone's digest is the same in both. Sparse sync works in both directions against zit's `horizon-rfc` revision. An implementation that predates horizons refuses a cone that carries one.
**Stock fossil 2.28.** A sparse store must not be served as if it were dense, because the clone would be silently incomplete. A store held sparsely is served only when its `partial-mirror` setting is on (`repo config set partial-mirror on`, `SettingPartialMirror`); otherwise it refuses. The refusal puts the push card ahead of the error so fossil 2.28 aborts instead of carrying on. Fossil cannot read [sub-manifest](/docs/concepts/sub-manifests/) check-ins either, so a repository that uses them is for libfossil and zit peers only.
## Limits
- **Compaction is irreversible locally.** `CompactStore` and `repo cone compact` delete held blobs (§5.4). Widening later fetches them again, which needs a peer that still has them. Structural artifacts, sub-manifest nodes, unsent or private content and the delta bases of retained artifacts are kept.
- **A sparse store lacks file content.** Commands that read an elided blob need a peer to fetch it, or fail.
- **A cone is not an authorization boundary** (§6.5). It limits what a store holds and asks for, not what a peer may read.
---
# Horizons
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/horizons/
A horizon cuts a store by time. It names a check-in **C**, a rule, and a depth. The check-ins the rule keeps are the **held set**. A blob is elided when no check-in in the held set names it. Structure (manifests, tags, control artifacts) is never elided by a content horizon.
A horizon is a member of a store cone, so everything on [Sparse cones](/docs/concepts/sparse-cones/) about store cones, elided artifacts and compaction applies to it too. The behaviour follows `draft-fossil-horizon-00`, implemented in step with zit.
The held set is computed from the check-in graph the repository holds. It is stored nowhere (§3.1).
## Rules
- **descendants** (the default): C and every check-in descended from it, through any parent, merges included.
- **leaves**: the descendants, plus, for every childless check-in that does not descend from C, every descendant of each check-in where its ancestry meets C's.
A check-in is childless when no other check-in names it as a parent, open or closed. A branch tip merged into another branch has a child, so it is not childless. Under the leaves rule, any two childless check-ins have their merge base in the held set, so merging branches that are still being extended never crosses the horizon. Both rules give a set that includes every child of every check-in in it.
The leaves rule has a cost you should check before using it. An old branch that was never merged forks from C's ancestry near the root, and the rule then holds every descendant of that fork. On fossil-scm.org's repository it held 20,907 of 21,008 check-ins at every depth tried. The descendants rule, with C 10, 100, 426 and 1000 check-ins back from the tip, saves 97, 86, 56 and 41 percent of that history (§3.4). Use the leaves rule when the repository keeps few old unmerged branches.
`repo cone cost <check-in>` (`Repo.HorizonCost`) reports what each rule would hold at a check-in, read from a repository that has the history:
```
$ libfossil -R repo.fossil repo cone cost trunk
horizon at trunk
descendants 1 check-ins, 3 blobs, 6 B expanded, 57 B stored
leaves 1 check-ins, 3 blobs, 6 B expanded, 57 B stored
```
## Depth
- **content** (the default): which blobs are held. Every check-in's structure is still held (§4).
- **structural** (`Horizon.Structural`, `--structural`): also cuts the manifests below C (§5). It needs a seed, a control artifact the origin mints so a clone can derive tag and branch state without C's ancestry.
A content horizon keeps all structure and elides only blobs; a structural horizon also leaves out the manifests below C.
## Signed seeds
An origin with the `clearsign` setting on (and the legacy `omitsign` off) signs each seed it mints with its `pgp-command`, the same settings fossil and zit sign check-ins with (§5.2.4). It keeps one signature per seed, so a seed keeps its name while the tag state it records is unchanged.
A clone given the origin's public key verifies every seed against it: at clone time, on every pull, and when it rebuilds. A seed that is unsigned, or signed by another key, is discarded and the clone falls back to the content horizon. A clone with no key accepts an unsigned seed. The key is the clone's own `horizon-seed-key` setting, never something the origin sends. `CloneOpts.SeedKey` and `repo clone --seed-key` set it when the clone is made; `Repo.SetConfig` refuses a value that is neither an SSH public key nor an OpenPGP fingerprint.
- **SSH:** the origin signs with `ssh-keygen -q -Y sign -n fossilscm -f KEY`; the clone's key is the public key line, verified in process.
- **PGP:** the origin signs with `gpg --clearsign -o`, fossil's default; the clone's key is the key's 40 or 64 digit fingerprint, verified by `gpg` against the user's keyring.
An origin signs only for a requester that may read, after the request is authorized, and keeps the signature in its own table; a store that cannot write, such as a read-only mirror, signs again for every request. Setting the origin's own `horizon-seed-key` to its public key makes it check a kept signature before serving it, so replacing the key behind an unchanged `pgp-command` takes effect at once. A clone that cannot run its verifier (gpg missing, or timed out) keeps the seed it holds and reports the error rather than falling back. Settings are read from the repository only: go-libfossil reads no global fossil configuration, so `clearsign` and `pgp-command` set with `fossil settings --global` do not apply.
[Signing](/docs/concepts/signing/) covers the signing settings and the verifier in more detail.
## Moving the horizon
Moving C earlier and pulling fetches what the deeper horizon keeps. Moving it later keeps what you hold until you compact. A horizon store cannot be a checkout's cone: a horizon governs what the repository holds, not which paths a checkout writes.
## Library usage
### Build a horizon cone
```go
h := libfossil.Horizon{
Checkin: "9f2c...", // full 40 or 64 digit hash
Rule: libfossil.HorizonDescendants, // or HorizonLeaves
Structural: false, // true for the structural cut
}
// Horizon only: every path, cut by time.
hc, err := libfossil.NewHorizonCone(nil, nil, h)
// Horizon plus paths.
hc, err = libfossil.NewHorizonCone([]string{"src"}, nil, h)
got, ok := hc.Horizon() // read it back
noHorizon, err := hc.WithHorizon(nil) // drop it, keep the paths
```
`Checkin` must be a full hash, and it is lower-cased. Dropping the horizon of a horizon-only cone is an error, since nothing would be left; use `SetStoreCone(nil)` to make the store dense.
### Clone into a horizon store
```go
t := libfossil.NewHTTPTransport("https://example.com/repo")
repo, res, err := libfossil.Clone(ctx, "repo.fossil", t, libfossil.CloneOpts{
StoreCone: hc,
SeedKey: "ssh-ed25519 AAAA...", // optional; structural only
})
if err != nil {
log.Fatal(err)
}
defer repo.Close()
fmt.Println(res.Elided, res.HorizonServed, res.StructuralServed, res.HorizonFallback)
```
- `HorizonServed`: replies where the server cut at the horizon (`pragma horizon-served`, §6.2.5). The other rounds were classified locally.
- `StructuralServed`: those served at the structural level.
- `HorizonFallback`: a structural clone kept the content horizon instead (§6.3).
`SyncResult` has the same fields.
### Clone by name or depth
A clone has no history yet, so it cannot turn a branch name or a count into C. It asks the origin, which resolves the name once, in its first reply (§6.2.7):
```go
repo, res, err := libfossil.Clone(ctx, "repo.fossil", t, libfossil.CloneOpts{
Horizon: &libfossil.Horizon{
Checkin: "trunk", // "tip", a branch or tag, or a full hash
Rule: libfossil.HorizonLeaves, // and Structural, as for any horizon
},
HorizonDepth: 100, // step back 100 check-ins along primary parents
})
fmt.Println(res.HorizonResolved, res.HorizonSteps, res.HorizonResolvedLocally)
```
- `tip` is the most recent check-in. A full hash names that check-in. Any other name is the most recent check-in carrying the tag `sym-NAME`, so branches and tags both work. Two check-ins with the same time resolve to the one with the lower full hash, so every origin resolves a name alike. Hash prefixes are not resolved.
- `HorizonDepth` steps back along primary parents. If history runs out first, C is the root it stopped at and `HorizonSteps` is less than the depth asked for.
- The store records only the resolved hash. Every later request of the clone, and every later pull, sync or deepen, sends that hash, never the name.
- A name the origin cannot resolve fails the clone with `horizon name not found: NAME`, and nothing is left on disk.
`CloneOpts.Horizon` takes the same `Horizon` as a store cone, except that its `Checkin` may be a name. `StoreCone` then gives only the path members: giving a horizon on both is an error, as is `HorizonDepth` without `Horizon`. A full hash is sent as a name too: the origin tries it as a check-in hash first and then as a branch or tag, so a branch spelled as 40 hex digits is found. A structural clone by name gets the seed the origin mints for the resolved C.
An origin resolves a name only for a requester that may read or clone. To anyone else it answers as if the request named no horizon, so whether a name exists cannot be learned from its replies.
An origin that does not answer the name (stock fossil, zit 0.7.0 and earlier) serves the clone densely. The clone then resolves the name itself over what it received, classifies locally at the content horizon, and reports `HorizonResolvedLocally`; a structural request falls back to the content horizon and reports `HorizonFallback` (§6.3).
`HorizonHistoryURL`, on both results, is the address the origin gives for querying history below the horizon outside the sync protocol, when it gives one. An origin sets it with `repo config set horizon-history-url https://...` (`SettingHorizonHistoryURL`); only one http or https URL with no spaces or credentials is accepted. `repo clone` prints it as `History:`.
### Deepen, merge across, and verify the seed
Setting, replacing and dropping a horizon on an existing store use `SetStoreCone` and `SetStoreConeContext`, as for any [store cone](/docs/concepts/sparse-cones/).
```go
// Move the horizon down far enough to reach a check-in, which may lie
// below it. C moves to that check-in when it is an ancestor of C, else to
// a common ancestor of the two, asked of the origin when the store cannot
// see one. The rule, the depth and the path members stay.
sr, err := repo.DeepenHorizon(ctx, target, libfossil.RequiredContentOpts{Peer: t})
// Merge. With a Peer, a merge where either side's ancestry crosses a
// structural horizon asks the origin for the base, deepening to it when it
// lies below. Without one it fails with an error matching
// libfossil.ErrBelowHorizon, even when the store finds a base it holds.
mr, err := co.MergeContext(ctx, libfossil.CheckoutMergeOpts{Version: rid},
libfossil.RequiredContentOpts{Peer: t})
// Check the seed against the history it summarizes. This fetches every
// manifest below C and leaves a content-horizon store.
v, err := repo.VerifySeed(ctx, libfossil.RequiredContentOpts{Peer: t})
```
Deepening a structural store discards its seed before it fetches the new one, so the old seed cannot shadow the new one. If the transfer fails, the old horizon and seed are put back (§5.8).
A merge never runs against a base the store does not hold. A bisection whose good end lies below the horizon is refused the same way, naming the horizon and the deepen.
An origin checks each pushed check-in that creates a branch: if the branch it cancels is not the one this origin derives for the parent, the clone's seed was stale, and the whole push is refused with `stale seed: ...` (§5.7). Pull, push a control artifact that cancels the parent's real branch tag on the check-in, and push again.
## Command line
### Clone a horizon store
```
libfossil repo clone URL repo.fossil --horizon <full hash>
libfossil repo clone URL repo.fossil --horizon trunk --depth 100
libfossil repo clone URL repo.fossil --horizon tip --leaves --cone src
libfossil repo clone URL repo.fossil --horizon release --structural --seed-key "ssh-ed25519 AAAA..."
```
- `--horizon=STRING`: clone a horizon store: elide blobs below this check-in, given as `tip`, a branch or tag, or its full 40 or 64 digit hash.
- `--depth=N`: with `--horizon`, step the check-in back N check-ins along primary parents, stopping at a root.
- `--leaves`: with `--horizon`, also hold every open leaf's ancestry back to the check-in.
- `--structural`: with `--horizon`, also elide the manifests below the check-in, deriving their branch and tag state from the origin's seed.
- `--seed-key=STRING`: the origin's public key, an SSH public key line or an OpenPGP fingerprint. With `--structural`, a seed not signed by it is discarded and the clone falls back to the content horizon. It is kept as the `horizon-seed-key` setting.
`--cone` and `--cone-not` combine with these. The origin resolves a name, since nothing is local yet to resolve it against, and the clone prints the check-in it resolved to as `Horizon at:`. A full hash is sent as a name too, so the origin can also find a branch or tag spelled as one. Later pulls, syncs and deepens send the resolved hash.
### Change the horizon
```
libfossil -R repo.fossil repo cone store --horizon <check-in>
libfossil -R repo.fossil repo cone store --horizon <check-in> --leaves
libfossil -R repo.fossil repo cone store --horizon <check-in> --structural
libfossil -R repo.fossil repo cone store --no-horizon
libfossil -R repo.fossil repo cone deepen <check-in>
libfossil -R repo.fossil repo cone cost <check-in>
```
- `--horizon=STRING`: elide blobs below this check-in (name, branch or hash prefix), fetching what a deeper horizon keeps. Unlike `clone`, a local name is fine.
- `--leaves`: with `--horizon`, also hold every open leaf's ancestry back to the check-in.
- `--structural`: with `--horizon`, also elide the manifests below the check-in; the next pull fetches the origin's seed.
- `--no-horizon`: drop the horizon, keeping the path members, and fetch what it elided.
- `cone deepen`: move the horizon down to reach the check-in, fetching what the deeper horizon keeps.
- `cone cost`: report what each rule would hold at the check-in, from this repository.
### Merge and verify
```
libfossil -R repo.fossil repo merge <version> -d DIR
libfossil -R repo.fossil repo verify --seed
```
- `merge`: a merge where either side's ancestry crosses a structural horizon asks the remote for the base, and deepens to it when it lies below. A merge whose ancestry stays above the horizon contacts no peer.
- `verify --seed`: verify the structural seed by fetching the history below the horizon. The store stays a content-horizon store.
`store`, `deepen`, `merge` and `verify` take `--remote` (default: the saved last-sync-url), `--sync-user`, `--sync-pass` (never saved), `--sync-private` and `--timeout` (default 10m; 0 disables it).
## Interoperability
**zit.** The horizon format matches zit's byte for byte. Horizon sync works in both directions against zit's `horizon-rfc` revision.
**Stock fossil 2.28.** A horizon store refuses a dense clone, because the clone would be silently incomplete.
**zit 0.7.1** resolves horizon names and depths as go-libfossil's origin does. Against zit 0.7.0 and earlier a clone by name falls back to resolving locally.
**A peer that knows nothing of horizons.** A horizon clone from stock Fossil works, by hash or by name. The client asks for nothing below the horizon, records the below-horizon blobs it is sent as elided instead of storing them, and classifies locally. `HorizonServed` stays 0. Stock Fossil can announce a new check-in only inside a cluster. A horizon store holds no clusters, so it requests the cluster members as transit and classifies what arrives (§4.5). Without that a new check-in would not be learned until a later one named it.
## Limits
- **The structural horizon needs an origin that serves it.** Against a peer that does not answer `horizon-served structural` (stock fossil, or a server without a current seed) the clone falls back to the content horizon and reports `HorizonFallback` (§6.3).
- **PGP verification needs gpg.** A PGP-signed seed is verified by running `gpg`, so a clone keyed with a fingerprint needs gpg installed and the key in its keyring; on js/wasm only SSH keys verify. gpg-agent hangs at start under a very large open-file limit, which a macOS shell can set to 2^31 (`ulimit -n`): lower it, to 4096 say, in the environment that signs or verifies with gpg.
- **The horizon cursor needs a transport that names its peer.** The cursor (`pragma horizon-cursor`, §6.2.6) lets an exchange skip re-announcing what both sides hold. The HTTP transport keys it by URL; a custom `Transport` keeps none and announces in full.
- **A horizon is not a checkout cone.** Give a checkout a horizon and you get `ErrHorizonCheckout`.
- **Compaction is irreversible locally.** `repo cone compact` drops the held blobs below the horizon; deepening later needs a peer that still has them.
---
# Signing
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/concepts/signing/
go-libfossil signs two kinds of artifact: check-ins, as fossil and zit sign them, and the seeds an origin mints for [structural horizons](/docs/concepts/horizons/). Both use the same settings and the same two envelopes, a PGP clear-signed message or the SSH envelope fossil builds around a detached `ssh-keygen` signature (`draft-fossil-artifact-format-00` §4.1.1).
## Settings
| Setting | Constant | Meaning |
|---|---|---|
| `clearsign` | `SettingClearsign` | Sign check-ins and horizon seeds. Off by default. |
| `omitsign` | | Fossil's legacy setting. On, it turns signing off again. |
| `pgp-command` | `SettingPGPCommand` | The signing command. Unset, it is fossil's default, `gpg --clearsign -o `. |
| `horizon-seed-key` | `SettingHorizonSeedKey` | The public key a clone verifies its origin's seeds with. |
Settings are read from the repository only. go-libfossil reads no global fossil configuration, so values set with `fossil settings --global` do not apply.
## Signing check-ins
With `clearsign` on, every check-in a commit or a branch creation stores is signed. The command runs as fossil runs it:
- **PGP:** `COMMAND OUTFILE INFILE`, which writes a clear-signed copy of the manifest.
- **SSH:** a command whose name starts with `ssh` runs as `COMMAND INFILE` and writes a detached `INFILE.sig`, which is wrapped in fossil's SSH envelope. The namespace must be `fossilscm`.
```
libfossil -R repo.fossil repo config set clearsign on
libfossil -R repo.fossil repo config set pgp-command \
"ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519"
```
The command runs through the shell, so `~` and environment variables expand. A signed check-in looks like this:
```
-----BEGIN SSH SIGNED MESSAGE-----
C signed
D 2026-10-23T20:45:21.089
F docs/x.md a09fd4d0...
...
Z 0e57ef44fd0eec16824d0a54ab247953
-----BEGIN SSH SIGNATURE-----
...
-----END SSH SIGNATURE-----
```
The stored bytes are the whole envelope, so the check-in's name is the hash of the signed bytes (§3.1). Readers strip the envelope before parsing, and the `Z` card covers the manifest inside it (§6.2).
To store one check-in unsigned, as fossil's `--nosign` does:
- `libfossil repo ci --nosign` and `libfossil repo branch new --nosign`.
- `CommitOpts.NoSign` (`Repo.Commit`) and `CheckoutCommitOpts.NoSign` (`Checkout.Checkin`).
### What fails
- **The signer fails or times out** (after two minutes). The commit is abandoned and nothing is stored.
- **The signer changes what it signs.** The envelope must strip back to exactly the manifest that was given, as zit checks it. A dash-escaped or rewritten manifest is refused rather than stored under a name its cards do not match.
- **On js/wasm** no external command can run, so signing fails there.
go-libfossil does not verify check-in signatures when it reads them. To check one, take the output of `libfossil repo cat` and run the signer's own verifier: `gpg --verify` on a PGP envelope, or, for SSH, `ssh-keygen -Y verify -n fossilscm -s SIG` with the manifest between the header and the signature block on standard input. The conformance test `TestSignedCheckin` checks that fossil and zit read the signed check-ins, and that a check-in zit signs with the same SSH key verifies here.
## Signing horizon seeds
An origin with `clearsign` on signs each structural horizon seed it mints with the same `pgp-command` (`draft-fossil-horizon-00` §5.2.4). It keeps one signature per seed in its own table, so a seed keeps its name while the tag state it records is unchanged. It signs only for a requester allowed to read, after the request is authorized. A store that cannot write, such as a read-only mirror, signs again for every request.
A clone verifies seeds against its `horizon-seed-key` setting:
```go
repo, res, err := libfossil.Clone(ctx, "repo.fossil", t, libfossil.CloneOpts{
StoreCone: hc, // a cone with a structural horizon
SeedKey: "ssh-ed25519 AAAA... origin",
})
```
```
libfossil repo clone URL repo.fossil --horizon <full hash> --structural \
--seed-key "ssh-ed25519 AAAA... origin"
```
The key is an SSH public key line, verified in process, or a 40 or 64 digit OpenPGP fingerprint, verified by `gpg` against the user's keyring. `Repo.SetConfig` refuses a `horizon-seed-key` that is neither. The key is the clone's own; the origin never sends it.
The clone verifies every seed it holds: at clone time, on every pull, and when it rebuilds.
| Seed | Key set | Result |
|---|---|---|
| Signed by the key | yes | Held. |
| Unsigned, or signed by another key | yes | Discarded; the store falls back to the content horizon. |
| Any | no | Held. A clone with no key accepts an unsigned seed. |
| Verifier could not run (gpg missing or timed out) | yes | The seed already held is kept and the error is reported. A new seed is refused. Nothing falls back. |
Setting the origin's own `horizon-seed-key` to its public key makes it check a kept signature before serving it, so replacing the key behind an unchanged `pgp-command` takes effect at once.
A signature proves where a seed came from, not that its derivation is right (§5.2.4). `repo verify --seed` (`Repo.VerifySeed`) checks the seed against the history it summarizes.
## Limits
- **PGP verification needs gpg** installed, with the origin's key in the keyring. On js/wasm only SSH keys verify.
- **gpg-agent hangs under a very large open-file limit.** A macOS shell can set `ulimit -n` to 2^31. Lower it, to 4096 say, in the environment that signs or verifies with gpg.
## Where the code is
- `signing.go`: the setting constants.
- `internal/clearsign`: running the signer, the SSH envelope, SSH verification in process, gpg verification.
- `internal/manifest/manifest.go`: signing a check-in before it is stored.
- `internal/sync/horizon_seedsign.go` and `internal/horizon/seed`: signing seeds at the origin and verifying them at the clone.
---
# Guides
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/
Task-oriented pages for running go-libfossil in a service, moving from fossil, and testing changes.
- [Production patterns](/docs/guides/production/): errors, contexts, telemetry, handle lifetime, driver choice.
- [Migrating from fossil](/docs/guides/migrating-from-fossil/): what carries over from the fossil binary and what differs.
- [Embedding the CLI](/docs/guides/cli-embedding/): driving `libfossil` as a child process.
- [Extension points](/docs/guides/extension-points/): observers, SQLite drivers and the `db.DB` abstraction.
- [Testing](/docs/guides/testing/): the test suite, deterministic simulation, fuzzing and interop.
---
# Production patterns
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/production/
The [Quickstart](/docs/get-started/quickstart/) uses `log.Fatal` to keep the snippets short. This page shows the patterns you'll actually want when libfossil is embedded in a service.
## Error handling
Don't `log.Fatal` from a long-running process — return errors up to a caller that can log, retry, or fail the request.
```go
func openRepo(path string) (*libfossil.Repo, error) {
repo, err := libfossil.Open(path)
if err != nil {
return nil, fmt.Errorf("open %s: %w", path, err)
}
return repo, nil
}
```
The errors you get back are wrapped Go errors; use `errors.Is` and `errors.As` against the sentinel errors exported from the [`libfossil` package](/docs/reference/sdk/libfossil/api/) when you need to branch on a specific failure (for example `ErrVersionNotFound`, `ErrAmbiguousVersion` or `ErrArtifactNotFound`).
## Context cancellation
`Sync`, `Pull`, and `Clone` accept a `context.Context`. Pass a request-scoped context with a deadline so a stalled remote doesn't tie up your goroutine forever.
```go
ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second)
defer cancel()
if _, err := repo.Sync(ctx, transport, libfossil.SyncOpts{Pull: true}); err != nil {
return fmt.Errorf("sync: %w", err)
}
```
The HTTP transport honors the deadline at the network boundary; the rest of the sync state machine checks `ctx.Done()` between rounds.
## Telemetry
Wire an observer to your Repo's operations to surface sync rounds, checkout events, and per-error events to your existing logging or metrics stack. See [Extension points](/docs/guides/extension-points/) for the full interface, and [`observer/otel`](/docs/reference/sdk/observer/otel/api/) for an OpenTelemetry-ready implementation that emits spans + counters.
```go
import (
libfossil "github.com/danmestas/go-libfossil"
otelobs "github.com/danmestas/go-libfossil/observer/otel"
)
obs := otelobs.NewSyncObserver()
_, err := repo.Sync(ctx, transport, libfossil.SyncOpts{
Pull: true,
Observer: obs,
})
```
`observer/otel` is a separate Go module so the OpenTelemetry SDK doesn't leak into consumers that don't want it.
## Repo handle lifetime
A `*Repo` wraps a SQLite database connection pool. Open it once at service startup, keep it for the lifetime of the process, and `Close()` it during shutdown — don't open and close per request.
```go
type service struct {
repo *libfossil.Repo
}
func newService(path string) (*service, error) {
repo, err := libfossil.Open(path)
if err != nil {
return nil, err
}
return &service{repo: repo}, nil
}
func (s *service) Shutdown() error {
return s.repo.Close()
}
```
Concurrent reads through one Repo are safe — SQLite handles the locking. Writes serialize at the database level (the drivers open write transactions with `BEGIN IMMEDIATE`, and a writer waits up to the 5-second busy timeout for the lock); if your service has heavy write traffic, queue write operations through a single goroutine rather than relying on lock contention to back-pressure.
## Driver selection
The shipped `cmd/libfossil` CLI uses `modernc` by default; `go build -tags test_ncruces ./cmd/libfossil` selects `ncruces`.
For library embedders targeting Linux/macOS/Windows, the default `modernc` driver is the right choice — pure Go, static binaries, no surprises. Switch to `ncruces` only when you're shipping a WASI/browser binary or when you need ncruces-specific behavior. Blank-import exactly one driver:
```go
import _ "github.com/danmestas/go-libfossil/db/driver/ncruces"
// Do not also import:
// _ "github.com/danmestas/go-libfossil/db/driver/modernc"
```
Drivers are mutually exclusive — a process can register exactly one. See [`db`](/docs/reference/sdk/db/api/) for the registry contract.
## Signing check-ins
With the `clearsign` setting on, every check-in that `Repo.Commit`, `Checkout.Checkin` or `repo branch new` stores is signed, as fossil and zit sign them. Fossil's legacy `omitsign` setting, when on, turns signing off again. The signer is the `pgp-command` setting, fossil's contract:
- **PGP:** unset, it is `gpg --clearsign -o `, run as `COMMAND OUTFILE INFILE`.
- **SSH:** a command whose name starts with `ssh`, such as `ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519`, is run as `COMMAND INFILE` and its detached signature is wrapped in fossil's SSH envelope. The namespace must be `fossilscm`.
```
libfossil -R repo.fossil repo config set clearsign on
libfossil -R repo.fossil repo config set pgp-command "ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519"
```
The signed text is the artifact, so a signed check-in is named by the hash of the signed bytes. Stock fossil and zit clone and read signed check-ins. A signer that fails abandons the commit. `CommitOpts.NoSign`, `CheckoutCommitOpts.NoSign` and `--nosign` store one check-in unsigned. The command runs through the shell, so `~` and environment variables expand. It runs inside the commit's transaction, so a signer that waits on a passphrase prompt holds the repository's write lock until it returns or two minutes pass. On js/wasm there is no external signer.
The same settings sign the horizon seeds an origin mints. A clone verifies them against the `horizon-seed-key` setting, which `repo clone --seed-key` (or `CloneOpts.SeedKey`) sets. See [Signing](/docs/concepts/signing/) for the envelope, verification and seed details.
---
# Migrating from fossil
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/migrating-from-fossil/
This guide is for users of upstream [Fossil SCM](https://fossil-scm.org) (the C
binary distributed by `fossil-scm.org`) who are evaluating `libfossil` — a
pure-Go implementation of the Fossil repository format and sync protocol.
It is intentionally honest about gaps. If a capability is not listed under
"Command coverage" below, assume it is not implemented yet.
For a structural overview of how libfossil is organised — the package layout, storage model, and pluggable axes — see [Architecture](/docs/concepts/architecture/).
## Repo format compatibility
`libfossil` reads and writes the same on-disk `.fossil` SQLite repository
format as upstream Fossil. A repository created by either tool can be opened
by the other at the file level — there is no import/export step and no data
migration is needed. Both implementations share the same blob table layout,
manifest/control artifact encoding, and delta chain representation.
One caveat: features introduced in very recent upstream Fossil releases
(bleeding-edge artifact card types, new Fossil-specific SQL functions used in
triggers) may not yet be parsed by `libfossil`. The tests that compare
against stock fossil run against the pinned release, 2.28. See
[Conformance](/docs/reference/conformance/) and [Testing](/docs/guides/testing/).
## Binary name and invocation
The compiled binary is named `libfossil` (not `fossil`) to avoid `$PATH`
collisions when both tools are installed on the same machine:
```
go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
```
`libfossil` uses a subcommand-grouped syntax: every command lives under the `repo` group,
and individual operations live beneath it. Upstream Fossil uses a flat
command style. Examples:
| Upstream Fossil | libfossil |
|------------------------------|----------------------------------------|
| `fossil clone URL repo.fossil` | `libfossil repo clone URL repo.fossil` |
| `fossil ci -m "msg" file.txt` | `libfossil -R repo.fossil repo ci -m "msg" file.txt` |
| `fossil timeline` | `libfossil -R repo.fossil repo timeline` |
The `-R <path>` flag selects the repository and is a global flag (before the
`repo` subcommand group).
## Command coverage
The following `repo` subcommands are implemented today. Every entry below
corresponds to a registered Kong command in `cli/repo.go` in the libfossil
source tree. `libfossil --help` lists them all.
### Repository creation
- `repo new` — create a new, empty repository file.
- `repo clone` — clone a remote Fossil server over HTTP(S). With `--cone`
it clones a sparse store; with `--structural` it derives branch and tag
state from the origin's horizon seed; `--seed-key` pins the key the seed
must be signed by. See [Sparse cones](/docs/concepts/sparse-cones/) and
[Horizons](/docs/concepts/horizons/).
### Working tree and checkout
- `repo open` — materialize a checkout in a directory (creates `.fslckout`).
- `repo co` — check out a named version.
- `repo ls` — list files in a version.
- `repo status` — show pending changes in the working directory.
- `repo add` — stage files for addition.
- `repo rm` — stage files for removal.
- `repo rename` — rename a tracked file.
- `repo revert` — undo staging changes.
- `repo ci` — commit the checkout's changes, or only the named files,
with any pending merge as a merge parent. `--nosign` stores one check-in
unsigned; see [Signing](/docs/concepts/signing/).
- `repo cone` — show or edit the checkout's sparse cone (`show`, `add`,
`remove`, `set`, `dense`, `test`) and the repository's store cone
(`store`, `deepen`, `compact`, `cost`).
### History and inspection
- `repo timeline` — repository history (`-n` sets the count, default 20).
- `repo log --path` — the check-ins that changed a path (`fossil finfo`).
- `repo snapshot` — commit one file's bytes onto trunk without a checkout;
see [Embedding the CLI](/docs/guides/cli-embedding/).
- `repo diff` — show changes vs. a version.
- `repo annotate` / `repo blame` — annotate file lines with commit history.
- `repo cat` — output artifact content.
- `repo hash` — hash files (SHA1 or SHA3-256).
- `repo info` — repository statistics.
- `repo resolve` — resolve a symbolic name to a UUID.
- `repo schema` — operate on the synced table schema.
- `repo query` — run ad-hoc SQL against the repository DB.
### Branching and merging
- `repo branch` — `ls`, `new` and `close`.
- `repo tag` — `ls` and `add`.
- `repo merge` — merge a divergent version into the current checkout.
- `repo conflicts` — `ls` lists files holding merge conflict markers and
conflict-fork entries; `show`, `pick`, `merge` and `extract` inspect and
resolve one conflicted file.
- `repo mark-resolved` — resolve a conflict-fork entry. A merge conflict
needs no marking: as in fossil, editing the markers out resolves it.
- `repo bisect` — binary-search commits for bug introductions (`good`,
`bad`, `next`, `skip`, `reset`, `ls`, `status`).
- `repo undo` / `repo redo` — undo/redo the last operation.
- `repo stash` — `save`, `pop`, `apply`, `ls`, `drop` and `clear`.
### Collaboration and admin
- `repo user` — user management.
- `repo invite` — generate an invite token for a user.
- `repo config` — get/set/list repository configuration.
- `repo wiki` — wiki page operations.
- `repo uv` — unversioned file operations.
- `repo extract` — extract files from a version.
- `repo delta` — create/apply delta operations.
- `repo verify` — verify repository integrity.
- `repo serve` — serve the repository over HTTP for clone and sync
(`-P host:port`, default `127.0.0.1:8080`). Access follows the user
table. It is a sync endpoint, not a web UI.
- `repo submanifests` — `enable`, `retune`, `disable` and `status` for
sub-manifest trees; see [Sub-manifests](/docs/concepts/sub-manifests/).
### Known gaps vs. upstream Fossil CLI
The following upstream commands have no `libfossil` equivalent today:
- `fossil ui` / `fossil http` — no web UI or HTTP admin server is shipped.
`repo serve` answers sync and clone requests only; it is the counterpart
of `fossil server` for the sync protocol and nothing else.
- `fossil sync` / `fossil push` / `fossil pull` — there is no CLI verb; sync
is exposed via the Go API (`Repo.Sync`, `Repo.Pull`, `Repo.XferHandler`)
but not as a subcommand.
- `fossil update` — merging a newer trunk into a checkout has no dedicated
CLI command; use `repo co` plus `repo merge` as needed.
- `fossil search` — no CLI front-end for full-text search.
- `fossil fts-config` / FTS index management — no CLI command.
## What's not supported yet
Beyond the gaps listed above, several broader features of upstream Fossil are
not yet exposed by `libfossil`:
- **Web UI / HTTP admin** — no equivalent of `fossil ui`. The sync protocol
handler exists as `Repo.XferHandler()` and `repo serve`, but the HTML UI,
wiki viewer, ticket tracker, and forum are not implemented.
- **Interactive conflict resolution** — there is no interactive merge
tool. `repo conflicts` lists, shows and resolves conflicts by picking a
version or re-merging; otherwise edit out fossil's conflict markers in
your editor.
- **Full-text search CLI** — `internal/search` contains indexing and query
primitives, but no CLI command surfaces them. Use the Go API directly.
- **Ticket and forum subsystems** — no commands or pages. Ticket and forum
artifacts are synced and stored like any other artifact.
- **Mirror / export bridges** to Git, svn, and other systems — not implemented.
If any of these are load-bearing for your workflow, stay on upstream Fossil
for now.
## Interop patterns
Where `libfossil` shines is in environments where the upstream C binary is
inconvenient to run:
- **CGo-free CI pipelines** — `libfossil` links statically with a pure-Go
SQLite driver (`db/driver/modernc`), so clone/sync steps work on stripped
container images and cross-compiled targets with no system dependencies.
- **Embedding in Go services** — the `Repo` handle can be used directly from
a Go program to read history, extract artifacts, or accept pushes over a
custom transport (WebSocket, NATS, libp2p).
- **WASI / browser deployments** — the `db/driver/ncruces` SQLite driver
compiles to WebAssembly, enabling repo access from edge runtimes.
See [Examples](/docs/examples/) for runnable starting points. The
`cmd/libfossil` package is also a short working example: `main.go` wires the
CLI, while `driver_modernc.go` registers the default driver and
`driver_ncruces.go` shows the tagged WebAssembly-capable alternative.
---
# Embedding the CLI
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/cli-embedding/
An application that keeps version history in a Fossil repository can run the `libfossil` binary as a child process: no checkout, no shadow working tree. `repo new` and four more commands make up the interface; their output and exit statuses are stable.
## Commands
```
libfossil -R repo.fossil repo new [--user U]
libfossil -R repo.fossil repo snapshot -m MSG [--user U] --path notes/x.md [--stdin] [--json]
libfossil -R repo.fossil repo log --path notes/x.md [--json] [-n N]
libfossil -R repo.fossil repo cat --at VERSION notes/x.md
libfossil -R repo.fossil repo diff [--json] A B [PATH]
```
**new** creates the repository file, empty and with no check-ins. The path is the `-R` path, or PATH as an argument (`repo new PATH`); when both are given PATH is the file created. With neither it exits 1. `--user U` names the admin user, which gets the setup capability; the default is the process's login name, as `fossil new` uses. The hash policy is `sha3`, fossil's default for a new repository, and the project code is generated. There is no flag for either. On success it prints `created repository: PATH` and a newline to stdout, exits 0, and leaves no file but the repository. Stock fossil 2.28 opens the result, and `fossil info`, `fossil sql` and `fossil hash-policy` read it.
`new` never overwrites. A file, an empty file or a directory already at PATH is refused with exit 1 and `repository already exists: PATH` on stderr, and what was there is untouched; `fossil new` also refuses an existing file, with exit 1. A PATH whose parent directory does not exist is refused with exit 1 and `parent directory does not exist: DIR` on stderr, and nothing is created; `fossil new` fails there with exit 1 as well, with a SQLite error. Create the parent first.
**snapshot** commits one file's bytes onto trunk and carries every other file forward. The bytes come from stdin with `--stdin`, otherwise from `--path` read on disk relative to the working directory. `--path` must be a name fossil accepts for a new file: a clean relative path (`notes/x.md`; not `/x`, `../x`, `./x`, `a//b`, `a/`, `a\b`) in valid UTF-8, with no control character (a byte below 0x20), and not one of the names fossil reserves for its own files (`_FOSSIL_` or `.fslckout`, in any case, with or without a `-wal`, `-shm` or `-journal` suffix, at the top or as the last element of the path). A rejected path exits 1 and says why. When the bytes equal the file at the trunk tip, nothing is committed and the existing tip is reported. The first snapshot into an empty repository becomes the root check-in. A repository that has check-ins but none on its main branch (`trunk`, or the branch the `main-branch` setting names) is refused with exit 1, rather than given a second, unrelated root. The check-in time is the current time.
**log** lists the check-ins that changed the path, newest first, as `fossil finfo` does. `-n` caps the count; the default is all.
**Paths.** `log --path`, `cat --at` and `diff` match a PATH as fossil does inside a check-out. They normalize it: a leading `./`, a trailing `/`, doubled `/` and `/./` or `/x/../` components are dropped, so `./Notes//A.md` and `Notes/A.md/` name `Notes/A.md`. They compare it with the repository's `case-sensitive` setting: when it is off, names that differ only in ASCII letter case are the same file, so `notes/a.md` finds `Notes/A.md`; `log` then merges the history of every name that matches, and `cat` reads the first matching file in the version. Without that setting the default is fossil's platform default: off on macOS and Windows, on elsewhere. Fossil also consults a global setting in `~/.fossil`; go-libfossil does not, so a `case-sensitive` set with `fossil settings --global` is ignored. A repository's names are never folded or rewritten, only matched. What is stored and printed is the name as the check-in recorded it.
A PATH is relative to the repository root, so there is no check-out for it to be outside of. `../x` and an absolute path such as `/x` are not special: they match no file, and exit 2 as not found. Fossil refuses them as outside the check-out and exits 1; go-libfossil keeps one status for every path that names nothing.
The exit status for a PATH or version that is not found is 2 in go-libfossil's own contract. `fossil` exits 1 for the same failures, so a caller that checks for 2 should not expect fossil's status.
A rename ends a name's history, as it does in `fossil finfo`. After `a.md` is renamed to `b.md`, `log --path b.md` lists the check-ins that changed `b.md`, then the rename itself (`action` `renamed`, `prev_name` `a.md`), and stops: it does not continue into `a.md`'s history. To follow a file across renames, run `log` again with `prev_name`. `log --path a.md` lists the rename first, as the check-in that removed `a.md` (`action` `deleted`), then `a.md`'s own changes. That first row is the one difference from `fossil finfo`, which lists only check-ins that hold a version of the file.
**cat** writes the file's bytes as VERSION holds them, as `fossil cat -r` does. VERSION is anything `repo resolve` accepts: `tip`, `trunk`, a branch, a uuid or a unique prefix of one. Without `--at`, `repo cat` still outputs an artifact by uuid.
**diff** with two versions prints the unified diff between them for PATH, or for every file that differs when PATH is omitted. PATH is matched as `fossil diff --from A --to B PATH` matches it: a file of that name, or every file under a directory of that name, in either version. A PATH that matches nothing in either version is not found (exit 2; fossil exits 1 with `not found`); a PATH that matches only unchanged files is an empty diff. With one or no version it compares the working directory, as before.
## Output
Every JSON document is a single line on stdout. Fields are never renamed or removed; new fields may be added, so parse tolerantly. Times are RFC 3339 in UTC with milliseconds, such as `2026-10-19T08:30:00.123Z`. A uuid is the repository's hash of the artifact (40 hex characters for SHA1, 64 for SHA3-256).
`snapshot` prints the check-in uuid and a newline. With `--json`:
```json
{"uuid": "9f2c...", "changed": true}
```
`changed` is false when the bytes already matched the tip and `uuid` is that tip.
`log --json` prints an array, newest first:
```json
[{"uuid": "9f2c...", "time": "2026-10-19T08:30:00.123Z", "user": "dan",
"comment": "edit", "action": "modified", "file_uuid": "ab12...", "prev_name": ""}]
```
`action` is `added`, `modified`, `deleted` or `renamed`. `file_uuid` is absent for `deleted`; `prev_name` is present only for `renamed`. Without `--json`, each line is `UUID10 TIME USER ACTION COMMENT`.
`diff --json A B [PATH]` prints an array, empty when nothing differs:
```json
[{"name": "notes/x.md", "unified": "--- a/notes/x.md\n+++ b/notes/x.md\n@@ ..."}]
```
## Exit statuses
| Status | Meaning |
| --- | --- |
| 0 | Success, including a `snapshot` that changed nothing and a `diff` with no differences. |
| 1 | Any other failure: a bad `--path`, an unreadable repository, an ambiguous version prefix, an I/O error. The message is on stderr. |
| 2 | Not found: the version does not resolve, the file is not in that version (`cat`), the path is in neither version (`diff`), or the path has no history (`log`). Nothing is written to stdout. |
| 80 | Usage error: an unknown command or flag, or a missing required flag or argument. The command-line parser sets this status and writes the error and the command's usage to stderr; stdout stays empty. |
These are the statuses of the `libfossil` binary itself. `go run ./cmd/libfossil` reports any non-zero status as 1, so measure them on a built binary. A combination the parser accepts but the command refuses, such as `diff --json` without two versions, exits 1.
## Concurrency
Processes may snapshot into one repository at the same time. A snapshot takes SQLite's write lock before it reads the trunk tip and keeps it until its check-in commits, so concurrent snapshots run one after another, form one linear trunk, and none loses another's files. A snapshot waits for the lock up to the busy timeout (5 seconds) and then fails with exit 1. Keep the repository outside any synced folder, and open it from one machine at a time.
---
# Extension points
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/extension-points/
libfossil exposes four surfaces for consumers that want to instrument, extend, or replace pieces of the stack:
1. **Observer interfaces** for sync and checkout lifecycle events (`SyncObserver`, `CheckoutObserver`).
2. **SQLite driver registration** (`db.Register`) — pick the SQLite backend at link time.
3. **The `db.DB` abstraction** — an opaque wrapper around `database/sql` with Fossil-specific helpers. Treat it as internal; it is less stable than the observer and driver surfaces.
4. **The `Transport` interface** — one method, `RoundTrip(ctx, payload) ([]byte, error)`, carries a sync round. `Repo.Sync` and `Clone` take any implementation, so sync can run over HTTP, WebSocket, NATS or an in-process pipe. `TransportFunc` adapts a plain function.
## Observer interfaces
Observers are the supported way to attach telemetry, logging, or metrics to a `Repo` without forking or wrapping the public API. Both interfaces are defined in the root `github.com/danmestas/go-libfossil` package and are context-free by design so that they can be reused across synchronous and asynchronous callers.
### `SyncObserver`
Source: `observer.go`.
```go
type SyncObserver interface {
Started(info SessionStart)
RoundStarted(round int)
RoundCompleted(round int, stats RoundStats)
Completed(info SessionEnd)
Error(err error)
HandleStarted(info HandleStart)
HandleCompleted(info HandleEnd)
TableSyncStarted(info TableSyncStart)
TableSyncCompleted(info TableSyncEnd)
}
```
| Method | Fires when |
|---|---|
| `Started` | A client-side sync or clone session begins, before any rounds run. |
| `RoundStarted` | A new sync round starts (there are typically multiple rounds per session). |
| `RoundCompleted` | A sync round finishes — `RoundStats` carries per-round totals. |
| `Completed` | The sync/clone session ends successfully. |
| `Error` | The sync machinery reports a per-error event (protocol or transport). |
| `HandleStarted` | Server-side: an inbound sync/clone HTTP request is accepted. |
| `HandleCompleted` | Server-side: an inbound sync/clone request finishes. |
| `TableSyncStarted` | An extension table sync (for example `peer_registry`) is about to run. |
| `TableSyncCompleted` | An extension table sync finishes. |
libfossil ships `NopSyncObserver()` and `StdoutSyncObserver()` (logs to stderr) as drop-in implementations.
### `CheckoutObserver`
Source: `observer.go`.
```go
type CheckoutObserver interface {
ExtractStarted(info ExtractStart)
ExtractFileCompleted(name string, change UpdateChange)
ExtractCompleted(info ExtractEnd)
ScanStarted(dir string)
ScanCompleted(info ScanEnd)
CommitStarted(info CommitStart)
CommitCompleted(info CommitEnd)
Error(err error)
}
```
| Method | Fires when |
|---|---|
| `ExtractStarted` | An extract or update begins writing files from a checkin into the working tree. |
| `ExtractFileCompleted` | One file has been written — `change` is `ChangeAdded`, `ChangeModified`, or `ChangeDeleted`. |
| `ExtractCompleted` | The extract/update finishes. |
| `ScanStarted` | A working-tree scan (status/change detection) begins for `dir`. |
| `ScanCompleted` | The working-tree scan finishes. |
| `CommitStarted` | A checkin commit begins after staging. |
| `CommitCompleted` | The commit lands — `info.UUID` and `info.RID` identify the new checkin. |
| `Error` | A per-error event fires from the checkout pipeline. |
### Minimal logging observer
```go
package main
import (
"log"
libfossil "github.com/danmestas/go-libfossil"
)
type logSync struct{ libfossil.SyncObserver } // embed nop for defaults
func (logSync) Started(info libfossil.SessionStart) {
log.Printf("sync start project=%s push=%v pull=%v", info.ProjectCode, info.Push, info.Pull)
}
func (logSync) RoundCompleted(round int, s libfossil.RoundStats) {
log.Printf("round %d sent=%d recv=%d", round, s.FilesSent, s.FilesRecvd)
}
func newLogSyncObserver() libfossil.SyncObserver {
return logSync{SyncObserver: libfossil.NopSyncObserver()}
}
```
The embedded `NopSyncObserver()` provides no-op implementations of the methods you do not override, so you only need to define the events you care about. The same pattern applies to `CheckoutObserver` via `NopCheckoutObserver()`; `StdoutCheckoutObserver()` is its stderr logger.
For a full real-world observer that emits spans and counters, see `observer/otel/otel.go`. It implements both interfaces and is the reference you should copy from when wiring up your own telemetry backend.
## Adding an OpenTelemetry (or other) observer
`observer/otel` lives in its own Go module (separate `go.mod`) so that the OpenTelemetry SDK dependency does not leak into consumers that do not want it. To use it, import the subpackage explicitly and hand the observer to each `Repo` operation that accepts one (`SyncOpts.Observer`, `CloneOpts.Observer`, `HandleOpts.Observer`, `CheckoutCreateOpts.Observer`, `CheckoutOpenOpts.Observer`).
```go
import (
libfossil "github.com/danmestas/go-libfossil"
"github.com/danmestas/go-libfossil/observer/otel"
)
obs := otel.NewSyncObserver() // implements libfossil.SyncObserver
_, err := repo.Sync(ctx, transport, libfossil.SyncOpts{
Pull: true,
Observer: obs,
})
```
`otel.NewCheckoutObserver()` returns the matching `CheckoutObserver`. Any third-party telemetry library (Prometheus, Datadog, zap, etc.) should be vendored the same way: a sibling module that imports `libfossil` and implements the observer interfaces.
## SQLite driver interface
Source: `db/register.go`, `db/db.go`, `db/doc.go`.
libfossil never imports a SQLite driver directly. Instead, the `db` package exposes a single registration hook that a driver package calls from its `init()`:
```go
// db/register.go
type DriverConfig struct {
Name string
BuildDSN func(path string, pragmas map[string]string) string
}
func Register(cfg DriverConfig)
```
Each `db.Open(path)` / `db.OpenWith(path, cfg)` call routes through the currently registered driver. Exactly one driver may be registered per process — `Register` panics if called twice, if `Name` is empty, or if `BuildDSN` is nil. Likewise, calling `Open` with no driver registered panics with a message pointing at the driver import paths.
The driver contract is intentionally small:
- **`Name`**: the name passed to `sql.Open`. The driver package is responsible for registering this name with `database/sql` (typically via a blank import of the underlying SQLite library).
- **`BuildDSN(path, pragmas)`**: return a DSN string that opens `path` and applies the given pragmas. libfossil calls `db.DefaultPragmas()` and merges any caller overrides before handing them to `BuildDSN`.
### Built-in drivers
| Driver | Import | When to use |
|---|---|---|
| `modernc` | `_ "github.com/danmestas/go-libfossil/db/driver/modernc"` | Default. Pure Go, no cgo, works on every `GOOS`/`GOARCH` libfossil supports. |
| `ncruces` | `_ "github.com/danmestas/go-libfossil/db/driver/ncruces"` | Uses `github.com/ncruces/go-sqlite3` (WASM-based SQLite). Pick this for WASM builds or environments where you need the ncruces feature set. |
### Registering a custom driver
Use this pattern when you want to wrap an instrumented SQLite build, redirect to a network-attached SQLite, or inject additional pragmas. Model the package after `db/driver/modernc/modernc.go`:
```go
package mydriver
import (
"fmt"
"strings"
"github.com/danmestas/go-libfossil/db"
_ "example.com/my/sqlite" // registers "mysqlite" with database/sql
)
func init() {
db.Register(db.DriverConfig{
Name: "mysqlite",
BuildDSN: buildDSN,
})
}
func buildDSN(path string, pragmas map[string]string) string {
var parts []string
for k, v := range pragmas {
parts = append(parts, fmt.Sprintf("_pragma=%s(%s)", k, v))
}
if len(parts) == 0 {
return path
}
return fmt.Sprintf("file:%s?%s", path, strings.Join(parts, "&"))
}
```
Consumers then blank-import your package (`_ "example.com/mydriver"`) exactly like they would for `modernc` or `ncruces`.
## The `DB` abstraction
`github.com/danmestas/go-libfossil/db` wraps `*sql.DB` with Fossil-aware helpers: DSN construction, default-pragma setup, WAL/nolock handling for WASM, transaction scoping via `DB.WithTx`, and the `Querier` interface (satisfied by both `DB` and `Tx`) so repository code can be written transaction-agnostic. The exported surface is stable for reading — `SqlDB()`, `Path()`, `Driver()`, `Exec`/`Query*` — but the struct itself is treated as internal: the public `Repo` API is the intended extension point. Prefer writing a custom driver (above) over implementing `DB` yourself. See `db/db.go`, `db/config.go`, and `db/scan.go` for the source of truth.
---
# Testing
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/guides/testing/
This guide describes libfossil's test strategy for contributors adding tests or
investigating failures. For the module layout referenced throughout, see
[Architecture](/docs/concepts/architecture/).
## Overview
libfossil's test suite has these layers:
1. **Unit tests** — standard `go test ./...` coverage for individual packages
under the root module and `internal/...`.
2. **Conformance tests** — `./conformance`, which checks the library against
the Fossil Internet-Drafts in `conformance/rfcs/`, requirement by
requirement, and against real `fossil` and `zit` binaries where they are
present. See [Conformance](/docs/reference/conformance/).
3. **DST simulation tests** — deterministic simulation scenarios under
`./dst/...` that drive multiple repos through a virtual clock with fault
injection and invariant checks.
4. **Fuzz targets** — Go native fuzz tests for the parsers and codecs.
5. **Dual-driver matrix** — the whole suite runs against two SQLite drivers
(`modernc` and `ncruces`) to catch driver-specific behavior.
## Running tests
The `Makefile` wraps the common targets:
- `make test` — runs `go test ./... -count=1 -timeout=120s` with the default
`modernc` driver.
- `make test-drivers` — runs the full suite twice:
`go test ./... -count=1 -timeout=120s` followed by
`go test -tags test_ncruces ./... -count=1 -timeout=120s`.
- `make test-otel` — runs the out-of-workspace OTel submodule with
`cd observer/otel && GOWORK=off go test ./... -count=1`.
- `make test-all` — chains `test-drivers`, `test-otel`, and `go build
./cmd/libfossil/`.
- `make ci` — mirrors `.github/workflows/test.yml`. It uses `GOWORK=off`,
runs the packages other than `dst` with a 120-second timeout, runs `./dst/...`
with a 300-second timeout, runs the driver submodule tests, `go vet` and
the CLI build, then repeats the tests under `-tags test_ncruces` and runs
the OTel submodule. Run it before opening a PR. `make release VERSION=vX.Y.Z`
runs it before it tags.
`make setup-hooks` points `core.hooksPath` at `.githooks/`. The installed
pre-commit hook runs both drivers with `-short`, `go vet`, the OTel submodule,
the CLI build, and a check that the generated SDK reference pages are in sync,
in roughly 45 seconds. Skip with `git commit --no-verify` only in emergencies.
Tests that compare against real binaries skip when the binary is missing.
`REQUIRE_FOSSIL_BIN=1` turns a missing `fossil` into a failure, and CI sets
it. `fossil` keeps a global config in `$HOME`, so run those tests with a
scratch `HOME` if you do not want your own touched.
## Fuzzing
There are seven fuzz targets. Each is also a regular test over its seed
corpus, so `go test` runs the seeds without `-fuzz`.
| Target | Package | Exercises |
|---|---|---|
| `FuzzUnified` | `internal/diff` | Unified diff output. |
| `FuzzTableSyncPayload` | `internal/sync` | Extension-table sync payload parsing. |
| `FuzzParseXDelete` | `internal/xfer` | The `xdelete` card parser. |
| `FuzzDecode` | `internal/xfer` | The xfer message decoder and its size limits. |
| `FuzzArtifactRoundTrip` | `conformance` | Artifact parse and re-encode. |
| `FuzzDeltaApply` | `conformance` | Applying arbitrary deltas. |
| `FuzzDeltaRoundTrip` | `conformance` | Delta create then apply. |
Run one with, for example:
```
go test ./conformance -run '^$' -fuzz FuzzDeltaApply -fuzztime 60s
```
CI does not run `-fuzz`, and no Makefile target or script runs the fuzz
targets or a seed sweep. They are run by hand.
## Corpus parity gate
`TestCloneCorpusParity` (root package, `clone_corpus_parity_test.go`) clones one
repository two ways — with the canonical `fossil` binary and with
`libfossil.Clone` — and compares what each derived. It is opt-in:
```
LIBFOSSIL_CORPUS_PARITY=1 go test -run TestCloneCorpusParity -v .
```
Without the variable it skips, so `make test` is unchanged in both runtime and
outcome. It also needs a fossil binary and skips without one (or fails, under
`REQUIRE_FOSSIL_BIN=1`). Budget roughly a second and under a megabyte of temp
space; everything lands in `t.TempDir()` and is removed on exit.
It exists because the per-package parity tests compare our derivation against
fossil's for fixtures built in-test, which only covers the shapes someone
thought to build. Issue #184 — a silent 100% loss of the ticket-change artifact
shape — passed that suite and was found by an external benchmark instead.
The gate asserts two things:
- **Per-`event`-type counts match**, not just the total. This distinction is the
point: on the real Fossil repository the totals read 23,396 vs 27,099, a 14%
shortfall easy to wave off, while the per-type breakdown put ticket events at
96 vs 3,808.
- **Row totals match for `blob`, `event`, `mlink`, `plink`, `tagxref` and
`leaf`**, reported in both directions. A surplus matters as much as a
shortfall — our `tagxref` ran +17,119 over fossil's on the real repository,
which is what writing a tag without finishing the work it marks looks like.
Failures name the table or type and the delta, e.g.
`event type "t": got 0, want 10 (-10)`.
The corpus is built by the canonical binary at test time rather than
downloaded: seconds and kilobytes instead of the ~10 minutes and ~1 GB the real
Fossil repository costs, no network dependency, and contents that are a
property of the test rather than of whatever a remote server holds today. It
covers check-ins (including a branch and a merge), ticket creations and
updates, a wiki page, a technote, an attachment, and a tag control artifact.
`requireCorpusShapes` classifies every blob by its card set and fails if any
shape falls below its expected floor. Without that check a corpus that quietly
stopped producing ticket artifacts would let the gate pass while covering
nothing — the exact blind spot it exists to remove.
Not covered: forum posts (`f` events), because fossil exposes no CLI to create
them; the scale-dependent behaviour of a large repository; and per-row content
comparison — this gate counts rows, and `internal/manifest` diffs them.
## Driver matrix
libfossil abstracts SQLite behind `db/` and two driver submodules. Both must
pass identical tests:
- **`modernc`** (default) — pure-Go port of SQLite. Used by every build
that doesn't set a tag. Registered via `internal/testdriver/modernc.go`
under `//go:build !test_ncruces && !test_mattn`.
- **`ncruces`** (wasm-capable) — selected with `-tags test_ncruces`, suitable
for WASM targets. Registered via `internal/testdriver/ncruces.go` under
`//go:build test_ncruces`.
GitHub Actions (`.github/workflows/test.yml`) runs `test`, `test-ncruces`,
`build-wasm`, `build-tinygo`, `test-otel` and `test-docs` as parallel jobs. The first two
install the pinned fossil 2.28, build every package, then run the unit tests,
DST and the driver submodule tests under modernc and ncruces respectively.
`build-wasm` compiles the packages for `js/wasm` with the ncruces tag,
`build-tinygo` builds `examples/tinygo` with TinyGo 0.43, and
`test-docs` builds this site with Hugo. For the canonical local invocation,
use `make test-drivers` or `make ci` rather than hand-rolling tag flags.
## DST (Deterministic Simulation Testing)
DST is inspired by FoundationDB and TigerBeetle: run many repos in a single
process under a simulated clock, inject faults, and replay a failing seed
deterministically. The harness lives in `dst/simulator.go` and
`dst/invariants.go`.
### Seeds and reproducibility
`dst.SimConfig.Seed` drives every random source used by the simulator: the
event queue, network fault decisions, and a `SeededBuggify` PRNG that gates
fault-injection sites. Any failure on seed N reproduces exactly on seed N.
`dst/scenario_test.go` exposes three flags driving `TestDST`:
```
go test ./dst -run 'TestDST$' -seed=42 -level=hostile -steps=10000
```
`TestDST` skips unless at least one flag is set. It builds a master repo
with 50 artifacts, 5 unversioned files and 3 private blobs, starts a
simulator with 3 leaves, and checks safety invariants as it runs.
- `-seed=<int64>` — seed passed to `SimConfig.Seed`. In `TestDST`, 0 means
seed 1; other scenarios use their own fixed seeds.
- `-level={normal,adversarial,hostile}` — picks a `severity` struct setting
`DropRate` and `Buggify`: `normal` is no drops and no BUGGIFY,
`adversarial` is 10% drops with BUGGIFY, `hostile` is 20% drops with
BUGGIFY. An empty or unknown level is `normal`.
- `-steps=<int>` — caps the number of events processed (default 10000 in
`TestDST`).
Seed-parameterized scenarios (e.g. `TestCloneDSTSeedSweep` in
`dst/clone_test.go`, which runs seeds 0 to 19) loop over seeds via `t.Run(fmt.Sprintf("seed_%d", seed),
...)`. To reproduce a single sub-seed: `go test ./dst -run
TestCloneDSTSeedSweep/seed_7 -v`.
### Invariants
`dst/invariants.go` defines per-node and cross-node checks. `Simulator.CheckSafety`
runs the per-node set after every `SafetyCheckInterval` steps; convergence
checks run once the sim has quiesced:
- **Safety (anytime):** `CheckBlobIntegrity` (UUID matches hash of expanded
content), `CheckDeltaChains` (`delta.srcid` resolves to a blob),
`CheckNoOrphanPhantoms`, `CheckUVIntegrity`, `CheckTableSyncIntegrity`.
`CheckTagxrefIntegrity` is a separate check that scenarios call
directly.
- **Convergence (after fault-free sync):** `CheckConvergence` (leaves match
master blob-for-blob), `CheckSubsetOf`, `CheckUVConvergence`,
`CheckTableSyncConvergence`, `CheckTombstoneConvergence`.
Failures return a `*InvariantError{Invariant, NodeID, Detail}` naming the
failing invariant and the offending node. The scenarios add the seed and
level to the failure message, so a log line is enough to replay the run.
The checks run with BUGGIFY suspended, so they see what is persisted and
not faults injected into their own reads.
## BUGGIFY
BUGGIFY marks code points where faults can be injected — shrunk send
budgets, dropped or rejected cards, bad nonces, byte-flipped content. About
twenty sites exist in `internal/sync`, `internal/blob` and
`internal/content`. In production
the check is a single boolean read; under DST the seeded PRNG decides whether
to fire.
Two styles appear in the tree:
1. **Process-global, used outside the sync path.** `simio.Buggify(probability)`
consults a process-global state toggled by `simio.EnableBuggify(seed)` /
`DisableBuggify()` (see `simio/buggify.go`). Example from
`internal/content/content.go`:
```go
// BUGGIFY: flip a byte in expanded content to exercise the hash check
// below under DST.
if check && simio.Buggify(0.01) && len(content) > 0 {
corrupted := make([]byte, len(content))
copy(corrupted, content)
corrupted[0] ^= 0xFF
content = corrupted
verified = false
}
```
2. **Scoped, passed through session options.** `BuggifyChecker` is an interface
(`Check(site string, probability float64) bool`) defined in
`internal/sync/session.go` and re-exported from the root as
`libfossil.BuggifyChecker`. Sync code threads a checker through so each site
has a stable name:
```go
// BUGGIFY: drop the last file card to simulate partial send.
if s.opts.Buggify != nil && s.opts.Buggify.Check("sync.buildFileCards.skip", 0.05) && len(cards) > 0 {
cards = cards[:len(cards)-1]
}
```
`dst.SeededBuggify` in `dst/simulator.go` implements `BuggifyChecker` with a
seeded `*rand.Rand` (it ignores the site name). `Simulator.New` enables both styles when `SimConfig.Buggify`
is true, wiring independent PRNG streams into the client, the server-side
`MockFossil`, and the global `simio` state.
## Interop with fossil 2.28 and zit
Two other implementations check libfossil's output.
**Fossil.** CI downloads the official fossil 2.28 release tarball
(`FOSSIL_VERSION` in `.github/workflows/test.yml`) and verifies its SHA-256
and its reported version, so every run compares against the same build.
Tests in `conformance/`, `cli/` and the root package create repositories with
stock `fossil`, have it open and verify what libfossil wrote, and compare
the rows libfossil derives with the rows fossil derives. Locally they use
the `fossil` on `PATH`; `fossil version` should report 2.28.
**zit.** zit is a Zig reimplementation of Fossil. The `TestZit*` tests in
`conformance/*zit*_test.go` (20 of them) cover the newer drafts: sub-manifest
trees (`zit_interop_test.go`, `zit_writer_test.go`), sparse cones and sparse
stores, and horizons (serve, structural seeds, fallback, push check, cursor,
nodes, history URL and merge base). Each runs both ways where it can:
go-libfossil clones from and pushes to `zit serve`, and zit clones from and
pushes to go-libfossil's handler. They need a `zit` on `PATH` (or `ZIT_BIN`)
at a recent enough commit and skip otherwise. `REQUIRE_ZIT_BIN=1` makes a
missing or older zit a failure. CI has no zit, so there the bundle tests
(`TestZitTreeBundle`, `TestZitWriterBundle`) read recorded copies of what
zit wrote from `conformance/testdata/`. `ZIT_REGENERATE=1` rewrites those
copies from a live zit.
Signed check-ins are covered the same way: `TestSignedCheckin` has fossil
and zit clone and read libfossil's signed check-ins, and checks that a
check-in zit signs verifies in libfossil.
## Writing new tests
- Prefer table-driven tests in unit code; include success and failure rows.
- If you touch sync, merge, clone, or checkin, add a DST scenario under
`dst/` and run it across a seed range (see `TestCloneDSTSeedSweep` for the
pattern).
- Mark any new fault-sensitive code point with BUGGIFY. Use the scoped
`BuggifyChecker` style when the site lives inside the sync session; reserve
`simio.Buggify` for code that runs outside an explicit session scope.
- Assert invariants. If the new behavior warrants one, add it to
`dst/invariants.go` and wire it into `CheckSafety` or a convergence helper.
- Confirm tests pass under both drivers (`make test-drivers`) before
requesting review.
---
# Reference
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/
Reference material, most of it generated from the source.
- [SDK](/docs/reference/sdk/): the Go API, one page per package, generated by gomarkdoc from doc comments.
- [CLI](/docs/reference/cli/): every `libfossil` command, generated from the binary's `--help` output.
- [Settings](/docs/reference/settings/): the repository settings go-libfossil reads.
- [Conformance](/docs/reference/conformance/): every requirement of every draft and its status, generated from `TestCoverage`.
---
# SDK
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/
Auto-generated Go API reference. One page per package, generated by [gomarkdoc](https://github.com/princjef/gomarkdoc) from doc comments.
Run `make docs-gen-sdk` to regenerate. The pre-commit hook fails if the working tree drifts.
---
# cli
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/cli/api/
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# cli
```go
import "github.com/danmestas/go-libfossil/cli"
```
## Index
- [func Version\(\) string](<#Version>)
- [type Globals](<#Globals>)
- [func \(g \*Globals\) OpenRepo\(\) \(\*libfossil.Repo, error\)](<#Globals.OpenRepo>)
- [type RepoAddCmd](<#RepoAddCmd>)
- [func \(c \*RepoAddCmd\) Run\(g \*Globals\) \(err error\)](<#RepoAddCmd.Run>)
- [type RepoAnnotateCmd](<#RepoAnnotateCmd>)
- [func \(c \*RepoAnnotateCmd\) Run\(g \*Globals\) error](<#RepoAnnotateCmd.Run>)
- [type RepoBisectBadCmd](<#RepoBisectBadCmd>)
- [func \(c \*RepoBisectBadCmd\) Run\(g \*Globals\) error](<#RepoBisectBadCmd.Run>)
- [type RepoBisectCmd](<#RepoBisectCmd>)
- [type RepoBisectGoodCmd](<#RepoBisectGoodCmd>)
- [func \(c \*RepoBisectGoodCmd\) Run\(g \*Globals\) error](<#RepoBisectGoodCmd.Run>)
- [type RepoBisectLsCmd](<#RepoBisectLsCmd>)
- [func \(c \*RepoBisectLsCmd\) Run\(g \*Globals\) error](<#RepoBisectLsCmd.Run>)
- [type RepoBisectNextCmd](<#RepoBisectNextCmd>)
- [func \(c \*RepoBisectNextCmd\) Run\(g \*Globals\) error](<#RepoBisectNextCmd.Run>)
- [type RepoBisectResetCmd](<#RepoBisectResetCmd>)
- [func \(c \*RepoBisectResetCmd\) Run\(g \*Globals\) error](<#RepoBisectResetCmd.Run>)
- [type RepoBisectSkipCmd](<#RepoBisectSkipCmd>)
- [func \(c \*RepoBisectSkipCmd\) Run\(g \*Globals\) error](<#RepoBisectSkipCmd.Run>)
- [type RepoBisectStatusCmd](<#RepoBisectStatusCmd>)
- [func \(c \*RepoBisectStatusCmd\) Run\(g \*Globals\) error](<#RepoBisectStatusCmd.Run>)
- [type RepoBlameCmd](<#RepoBlameCmd>)
- [type RepoBranchCloseCmd](<#RepoBranchCloseCmd>)
- [func \(c \*RepoBranchCloseCmd\) Run\(g \*Globals\) error](<#RepoBranchCloseCmd.Run>)
- [type RepoBranchCmd](<#RepoBranchCmd>)
- [type RepoBranchLsCmd](<#RepoBranchLsCmd>)
- [func \(c \*RepoBranchLsCmd\) Run\(g \*Globals\) error](<#RepoBranchLsCmd.Run>)
- [type RepoBranchNewCmd](<#RepoBranchNewCmd>)
- [func \(c \*RepoBranchNewCmd\) Run\(g \*Globals\) error](<#RepoBranchNewCmd.Run>)
- [type RepoCatCmd](<#RepoCatCmd>)
- [func \(c \*RepoCatCmd\) Run\(g \*Globals\) error](<#RepoCatCmd.Run>)
- [type RepoCiCmd](<#RepoCiCmd>)
- [func \(c \*RepoCiCmd\) Run\(g \*Globals\) \(err error\)](<#RepoCiCmd.Run>)
- [type RepoCloneCmd](<#RepoCloneCmd>)
- [func \(c \*RepoCloneCmd\) Run\(g \*Globals\) error](<#RepoCloneCmd.Run>)
- [type RepoCmd](<#RepoCmd>)
- [type RepoCoCmd](<#RepoCoCmd>)
- [func \(c \*RepoCoCmd\) Run\(g \*Globals\) error](<#RepoCoCmd.Run>)
- [type RepoConfigCmd](<#RepoConfigCmd>)
- [type RepoConfigGetCmd](<#RepoConfigGetCmd>)
- [func \(c \*RepoConfigGetCmd\) Run\(g \*Globals\) error](<#RepoConfigGetCmd.Run>)
- [type RepoConfigLsCmd](<#RepoConfigLsCmd>)
- [func \(c \*RepoConfigLsCmd\) Run\(g \*Globals\) error](<#RepoConfigLsCmd.Run>)
- [type RepoConfigSetCmd](<#RepoConfigSetCmd>)
- [func \(c \*RepoConfigSetCmd\) Run\(g \*Globals\) error](<#RepoConfigSetCmd.Run>)
- [type RepoConflictsCmd](<#RepoConflictsCmd>)
- [type RepoConflictsExtractCmd](<#RepoConflictsExtractCmd>)
- [func \(c \*RepoConflictsExtractCmd\) Run\(g \*Globals\) error](<#RepoConflictsExtractCmd.Run>)
- [type RepoConflictsLsCmd](<#RepoConflictsLsCmd>)
- [func \(c \*RepoConflictsLsCmd\) Run\(g \*Globals\) error](<#RepoConflictsLsCmd.Run>)
- [type RepoConflictsMergeCmd](<#RepoConflictsMergeCmd>)
- [func \(c \*RepoConflictsMergeCmd\) Run\(g \*Globals\) error](<#RepoConflictsMergeCmd.Run>)
- [type RepoConflictsPickCmd](<#RepoConflictsPickCmd>)
- [func \(c \*RepoConflictsPickCmd\) Run\(g \*Globals\) error](<#RepoConflictsPickCmd.Run>)
- [type RepoConflictsShowCmd](<#RepoConflictsShowCmd>)
- [func \(c \*RepoConflictsShowCmd\) Run\(g \*Globals\) error](<#RepoConflictsShowCmd.Run>)
- [type RepoDeltaApplyCmd](<#RepoDeltaApplyCmd>)
- [func \(c \*RepoDeltaApplyCmd\) Run\(g \*Globals\) error](<#RepoDeltaApplyCmd.Run>)
- [type RepoDeltaCmd](<#RepoDeltaCmd>)
- [type RepoDeltaCreateCmd](<#RepoDeltaCreateCmd>)
- [func \(c \*RepoDeltaCreateCmd\) Run\(g \*Globals\) error](<#RepoDeltaCreateCmd.Run>)
- [type RepoDiffCmd](<#RepoDiffCmd>)
- [func \(c \*RepoDiffCmd\) Run\(g \*Globals\) error](<#RepoDiffCmd.Run>)
- [type RepoExtractCmd](<#RepoExtractCmd>)
- [func \(c \*RepoExtractCmd\) Run\(g \*Globals\) error](<#RepoExtractCmd.Run>)
- [type RepoHashCmd](<#RepoHashCmd>)
- [func \(c \*RepoHashCmd\) Run\(g \*Globals\) error](<#RepoHashCmd.Run>)
- [type RepoInfoCmd](<#RepoInfoCmd>)
- [func \(c \*RepoInfoCmd\) Run\(g \*Globals\) error](<#RepoInfoCmd.Run>)
- [type RepoInviteCmd](<#RepoInviteCmd>)
- [func \(c \*RepoInviteCmd\) Run\(g \*Globals\) error](<#RepoInviteCmd.Run>)
- [type RepoLsCmd](<#RepoLsCmd>)
- [func \(c \*RepoLsCmd\) Run\(g \*Globals\) error](<#RepoLsCmd.Run>)
- [type RepoMergeCmd](<#RepoMergeCmd>)
- [func \(c \*RepoMergeCmd\) Run\(g \*Globals\) \(err error\)](<#RepoMergeCmd.Run>)
- [type RepoMergeResolveCmd](<#RepoMergeResolveCmd>)
- [func \(c \*RepoMergeResolveCmd\) Run\(g \*Globals\) \(err error\)](<#RepoMergeResolveCmd.Run>)
- [type RepoNewCmd](<#RepoNewCmd>)
- [func \(c \*RepoNewCmd\) Run\(g \*Globals\) error](<#RepoNewCmd.Run>)
- [type RepoOpenCmd](<#RepoOpenCmd>)
- [func \(c \*RepoOpenCmd\) Run\(g \*Globals\) error](<#RepoOpenCmd.Run>)
- [type RepoQueryCmd](<#RepoQueryCmd>)
- [func \(c \*RepoQueryCmd\) Run\(g \*Globals\) error](<#RepoQueryCmd.Run>)
- [type RepoRedoCmd](<#RepoRedoCmd>)
- [func \(c \*RepoRedoCmd\) Run\(g \*Globals\) error](<#RepoRedoCmd.Run>)
- [type RepoRenameCmd](<#RepoRenameCmd>)
- [func \(c \*RepoRenameCmd\) Run\(g \*Globals\) \(err error\)](<#RepoRenameCmd.Run>)
- [type RepoResolveCmd](<#RepoResolveCmd>)
- [func \(c \*RepoResolveCmd\) Run\(g \*Globals\) error](<#RepoResolveCmd.Run>)
- [type RepoRevertCmd](<#RepoRevertCmd>)
- [func \(c \*RepoRevertCmd\) Run\(g \*Globals\) \(err error\)](<#RepoRevertCmd.Run>)
- [type RepoRmCmd](<#RepoRmCmd>)
- [func \(c \*RepoRmCmd\) Run\(g \*Globals\) \(err error\)](<#RepoRmCmd.Run>)
- [type RepoSchemaAddCmd](<#RepoSchemaAddCmd>)
- [func \(c \*RepoSchemaAddCmd\) Run\(g \*Globals\) error](<#RepoSchemaAddCmd.Run>)
- [type RepoSchemaCmd](<#RepoSchemaCmd>)
- [type RepoSchemaListCmd](<#RepoSchemaListCmd>)
- [func \(c \*RepoSchemaListCmd\) Run\(g \*Globals\) error](<#RepoSchemaListCmd.Run>)
- [type RepoSchemaRemoveCmd](<#RepoSchemaRemoveCmd>)
- [func \(c \*RepoSchemaRemoveCmd\) Run\(g \*Globals\) error](<#RepoSchemaRemoveCmd.Run>)
- [type RepoSchemaShowCmd](<#RepoSchemaShowCmd>)
- [func \(c \*RepoSchemaShowCmd\) Run\(g \*Globals\) error](<#RepoSchemaShowCmd.Run>)
- [type RepoServeCmd](<#RepoServeCmd>)
- [func \(c \*RepoServeCmd\) Run\(g \*Globals\) error](<#RepoServeCmd.Run>)
- [type RepoStashApplyCmd](<#RepoStashApplyCmd>)
- [func \(c \*RepoStashApplyCmd\) Run\(g \*Globals\) error](<#RepoStashApplyCmd.Run>)
- [type RepoStashClearCmd](<#RepoStashClearCmd>)
- [func \(c \*RepoStashClearCmd\) Run\(g \*Globals\) error](<#RepoStashClearCmd.Run>)
- [type RepoStashCmd](<#RepoStashCmd>)
- [type RepoStashDropCmd](<#RepoStashDropCmd>)
- [func \(c \*RepoStashDropCmd\) Run\(g \*Globals\) error](<#RepoStashDropCmd.Run>)
- [type RepoStashLsCmd](<#RepoStashLsCmd>)
- [func \(c \*RepoStashLsCmd\) Run\(g \*Globals\) error](<#RepoStashLsCmd.Run>)
- [type RepoStashPopCmd](<#RepoStashPopCmd>)
- [func \(c \*RepoStashPopCmd\) Run\(g \*Globals\) error](<#RepoStashPopCmd.Run>)
- [type RepoStashSaveCmd](<#RepoStashSaveCmd>)
- [func \(c \*RepoStashSaveCmd\) Run\(g \*Globals\) error](<#RepoStashSaveCmd.Run>)
- [type RepoStatusCmd](<#RepoStatusCmd>)
- [func \(c \*RepoStatusCmd\) Run\(g \*Globals\) error](<#RepoStatusCmd.Run>)
- [type RepoSubmanifestsCmd](<#RepoSubmanifestsCmd>)
- [type RepoSubmanifestsDisableCmd](<#RepoSubmanifestsDisableCmd>)
- [func \(c \*RepoSubmanifestsDisableCmd\) Run\(g \*Globals\) error](<#RepoSubmanifestsDisableCmd.Run>)
- [type RepoSubmanifestsEnableCmd](<#RepoSubmanifestsEnableCmd>)
- [func \(c \*RepoSubmanifestsEnableCmd\) Run\(g \*Globals\) error](<#RepoSubmanifestsEnableCmd.Run>)
- [type RepoSubmanifestsRetuneCmd](<#RepoSubmanifestsRetuneCmd>)
- [func \(c \*RepoSubmanifestsRetuneCmd\) Run\(g \*Globals\) error](<#RepoSubmanifestsRetuneCmd.Run>)
- [type RepoSubmanifestsStatusCmd](<#RepoSubmanifestsStatusCmd>)
- [func \(c \*RepoSubmanifestsStatusCmd\) Run\(g \*Globals\) error](<#RepoSubmanifestsStatusCmd.Run>)
- [type RepoTagAddCmd](<#RepoTagAddCmd>)
- [func \(c \*RepoTagAddCmd\) Run\(g \*Globals\) error](<#RepoTagAddCmd.Run>)
- [type RepoTagCmd](<#RepoTagCmd>)
- [type RepoTagLsCmd](<#RepoTagLsCmd>)
- [func \(c \*RepoTagLsCmd\) Run\(g \*Globals\) error](<#RepoTagLsCmd.Run>)
- [type RepoTimelineCmd](<#RepoTimelineCmd>)
- [func \(c \*RepoTimelineCmd\) Run\(g \*Globals\) error](<#RepoTimelineCmd.Run>)
- [type RepoUVCmd](<#RepoUVCmd>)
- [type RepoUVDeleteCmd](<#RepoUVDeleteCmd>)
- [func \(c \*RepoUVDeleteCmd\) Run\(g \*Globals\) error](<#RepoUVDeleteCmd.Run>)
- [type RepoUVGetCmd](<#RepoUVGetCmd>)
- [func \(c \*RepoUVGetCmd\) Run\(g \*Globals\) error](<#RepoUVGetCmd.Run>)
- [type RepoUVLsCmd](<#RepoUVLsCmd>)
- [func \(c \*RepoUVLsCmd\) Run\(g \*Globals\) error](<#RepoUVLsCmd.Run>)
- [type RepoUVPutCmd](<#RepoUVPutCmd>)
- [func \(c \*RepoUVPutCmd\) Run\(g \*Globals\) error](<#RepoUVPutCmd.Run>)
- [type RepoUndoCmd](<#RepoUndoCmd>)
- [func \(c \*RepoUndoCmd\) Run\(g \*Globals\) error](<#RepoUndoCmd.Run>)
- [type RepoUserCmd](<#RepoUserCmd>)
- [type RepoVerifyCmd](<#RepoVerifyCmd>)
- [func \(c \*RepoVerifyCmd\) Run\(g \*Globals\) error](<#RepoVerifyCmd.Run>)
- [type RepoWikiCmd](<#RepoWikiCmd>)
- [type RepoWikiExportCmd](<#RepoWikiExportCmd>)
- [func \(c \*RepoWikiExportCmd\) Run\(g \*Globals\) error](<#RepoWikiExportCmd.Run>)
- [type RepoWikiLsCmd](<#RepoWikiLsCmd>)
- [func \(c \*RepoWikiLsCmd\) Run\(g \*Globals\) error](<#RepoWikiLsCmd.Run>)
- [type UserAddCmd](<#UserAddCmd>)
- [func \(c \*UserAddCmd\) Run\(g \*Globals\) error](<#UserAddCmd.Run>)
- [type UserListCmd](<#UserListCmd>)
- [func \(c \*UserListCmd\) Run\(g \*Globals\) error](<#UserListCmd.Run>)
- [type UserPasswdCmd](<#UserPasswdCmd>)
- [func \(c \*UserPasswdCmd\) Run\(g \*Globals\) error](<#UserPasswdCmd.Run>)
- [type UserRmCmd](<#UserRmCmd>)
- [func \(c \*UserRmCmd\) Run\(g \*Globals\) error](<#UserRmCmd.Run>)
- [type UserUpdateCmd](<#UserUpdateCmd>)
- [func \(c \*UserUpdateCmd\) Run\(g \*Globals\) error](<#UserUpdateCmd.Run>)
- [type VersionCmd](<#VersionCmd>)
- [func \(c \*VersionCmd\) Run\(\) error](<#VersionCmd.Run>)
<a name="Version"></a>
## func [Version](<https://github.com/danmestas/go-libfossil/blob/main/cli/version.go#L68>)
```go
func Version() string
```
Version returns a single\-line build identifier for this binary: the module version \(or a build\-time override\), the Go toolchain version, and the platform. The shape is fixed at four whitespace\-separated fields \-\- "libfossil \<version\> \<go version\> \<os\>/\<arch\>" \-\- regardless of which fields carried real data, so a caller can rely on strings.Fields\(Version\(\)\) unconditionally. This is the same string both \`libfossil version\` and \`libfossil \-\-version\` print.
<a name="Globals"></a>
## type [Globals](<https://github.com/danmestas/go-libfossil/blob/main/cli/shared.go#L16-L19>)
Globals holds flags shared by all CLI commands.
```go
type Globals struct {
Repo string `short:"R" help:"Path to repository file" type:"path"`
Verbose bool `short:"v" help:"Verbose output"`
}
```
<a name="Globals.OpenRepo"></a>
### func \(\*Globals\) [OpenRepo](<https://github.com/danmestas/go-libfossil/blob/main/cli/shared.go#L23>)
```go
func (g *Globals) OpenRepo() (*libfossil.Repo, error)
```
OpenRepo opens a Fossil repository using the handle API. If Repo is empty, it searches for a .fossil file or .fslckout checkout.
<a name="RepoAddCmd"></a>
## type [RepoAddCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_add.go#L9-L12>)
RepoAddCmd stages files for addition in the checkout database.
```go
type RepoAddCmd struct {
Files []string `arg:"" required:"" help:"Files to stage for addition"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoAddCmd.Run"></a>
### func \(\*RepoAddCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_add.go#L14>)
```go
func (c *RepoAddCmd) Run(g *Globals) (err error)
```
<a name="RepoAnnotateCmd"></a>
## type [RepoAnnotateCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_annotate.go#L10-L13>)
RepoAnnotateCmd annotates file lines with version history.
```go
type RepoAnnotateCmd struct {
File string `arg:"" required:"" help:"File to annotate"`
Version string `help:"Starting version (default: tip)"`
}
```
<a name="RepoAnnotateCmd.Run"></a>
### func \(\*RepoAnnotateCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_annotate.go#L15>)
```go
func (c *RepoAnnotateCmd) Run(g *Globals) error
```
<a name="RepoBisectBadCmd"></a>
## type [RepoBisectBadCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L27-L30>)
RepoBisectBadCmd marks a version as bad.
```go
type RepoBisectBadCmd struct {
Version string `arg:"" optional:"" help:"Version to mark (default: current checkout)"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectBadCmd.Run"></a>
### func \(\*RepoBisectBadCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L32>)
```go
func (c *RepoBisectBadCmd) Run(g *Globals) error
```
<a name="RepoBisectCmd"></a>
## type [RepoBisectCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L6-L14>)
RepoBisectCmd groups binary search operations.
```go
type RepoBisectCmd struct {
Good RepoBisectGoodCmd `cmd:"" help:"Mark version as good"`
Bad RepoBisectBadCmd `cmd:"" help:"Mark version as bad"`
Next RepoBisectNextCmd `cmd:"" help:"Check out midpoint version"`
Skip RepoBisectSkipCmd `cmd:"" help:"Skip current version"`
Reset RepoBisectResetCmd `cmd:"" help:"Clear bisect state"`
Ls RepoBisectLsCmd `cmd:"" help:"Show bisect path"`
Status RepoBisectStatusCmd `cmd:"" help:"Show bisect state"`
}
```
<a name="RepoBisectGoodCmd"></a>
## type [RepoBisectGoodCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L17-L20>)
RepoBisectGoodCmd marks a version as good.
```go
type RepoBisectGoodCmd struct {
Version string `arg:"" optional:"" help:"Version to mark (default: current checkout)"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectGoodCmd.Run"></a>
### func \(\*RepoBisectGoodCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L22>)
```go
func (c *RepoBisectGoodCmd) Run(g *Globals) error
```
<a name="RepoBisectLsCmd"></a>
## type [RepoBisectLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L65-L67>)
RepoBisectLsCmd shows the bisect path.
```go
type RepoBisectLsCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectLsCmd.Run"></a>
### func \(\*RepoBisectLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L69>)
```go
func (c *RepoBisectLsCmd) Run(g *Globals) error
```
<a name="RepoBisectNextCmd"></a>
## type [RepoBisectNextCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L47-L49>)
RepoBisectNextCmd checks out the bisect midpoint version.
```go
type RepoBisectNextCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectNextCmd.Run"></a>
### func \(\*RepoBisectNextCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L51>)
```go
func (c *RepoBisectNextCmd) Run(g *Globals) error
```
<a name="RepoBisectResetCmd"></a>
## type [RepoBisectResetCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L56-L58>)
RepoBisectResetCmd clears bisect state.
```go
type RepoBisectResetCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectResetCmd.Run"></a>
### func \(\*RepoBisectResetCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L60>)
```go
func (c *RepoBisectResetCmd) Run(g *Globals) error
```
<a name="RepoBisectSkipCmd"></a>
## type [RepoBisectSkipCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L37-L40>)
RepoBisectSkipCmd skips the current version.
```go
type RepoBisectSkipCmd struct {
Version string `arg:"" optional:"" help:"Version to skip (default: current checkout)"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectSkipCmd.Run"></a>
### func \(\*RepoBisectSkipCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L42>)
```go
func (c *RepoBisectSkipCmd) Run(g *Globals) error
```
<a name="RepoBisectStatusCmd"></a>
## type [RepoBisectStatusCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L74-L76>)
RepoBisectStatusCmd shows bisect state.
```go
type RepoBisectStatusCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoBisectStatusCmd.Run"></a>
### func \(\*RepoBisectStatusCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_bisect.go#L78>)
```go
func (c *RepoBisectStatusCmd) Run(g *Globals) error
```
<a name="RepoBlameCmd"></a>
## type [RepoBlameCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_annotate.go#L47-L49>)
RepoBlameCmd is an alias for annotate.
```go
type RepoBlameCmd struct {
RepoAnnotateCmd
}
```
<a name="RepoBranchCloseCmd"></a>
## type [RepoBranchCloseCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L169-L172>)
RepoBranchCloseCmd closes a branch.
```go
type RepoBranchCloseCmd struct {
Name string `arg:"" help:"Branch name to close"`
User string `help:"User for control artifacts (default: OS username)"`
}
```
<a name="RepoBranchCloseCmd.Run"></a>
### func \(\*RepoBranchCloseCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L174>)
```go
func (c *RepoBranchCloseCmd) Run(g *Globals) error
```
<a name="RepoBranchCmd"></a>
## type [RepoBranchCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L14-L18>)
RepoBranchCmd groups branch operations.
```go
type RepoBranchCmd struct {
Ls RepoBranchLsCmd `cmd:"" help:"List branches"`
New RepoBranchNewCmd `cmd:"" help:"Create new branch"`
Close RepoBranchCloseCmd `cmd:"" help:"Close a branch"`
}
```
<a name="RepoBranchLsCmd"></a>
## type [RepoBranchLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L21-L24>)
RepoBranchLsCmd lists branches.
```go
type RepoBranchLsCmd struct {
Closed bool `help:"Show only closed branches"`
All bool `help:"Show all branches (open and closed)"`
}
```
<a name="RepoBranchLsCmd.Run"></a>
### func \(\*RepoBranchLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L26>)
```go
func (c *RepoBranchLsCmd) Run(g *Globals) error
```
<a name="RepoBranchNewCmd"></a>
## type [RepoBranchNewCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L93-L98>)
RepoBranchNewCmd creates a new branch.
```go
type RepoBranchNewCmd struct {
Name string `arg:"" help:"Branch name"`
From string `help:"Parent version (default: tip)"`
Message string `short:"m" help:"Checkin comment"`
User string `help:"Checkin user (default: OS username)"`
}
```
<a name="RepoBranchNewCmd.Run"></a>
### func \(\*RepoBranchNewCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_branch.go#L100>)
```go
func (c *RepoBranchNewCmd) Run(g *Globals) error
```
<a name="RepoCatCmd"></a>
## type [RepoCatCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_cat.go#L13-L16>)
RepoCatCmd outputs the content of an artifact.
```go
type RepoCatCmd struct {
Artifact string `arg:"" help:"Artifact UUID or prefix"`
Raw bool `help:"Output raw blob (no delta expansion)"`
}
```
<a name="RepoCatCmd.Run"></a>
### func \(\*RepoCatCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_cat.go#L18>)
```go
func (c *RepoCatCmd) Run(g *Globals) error
```
<a name="RepoCiCmd"></a>
## type [RepoCiCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_ci.go#L13-L21>)
RepoCiCmd commits the checkout's changes, as fossil's commit command does: every change, or only the named files. A pending merge is committed with the merged\-in checkin as a merge parent.
```go
type RepoCiCmd struct {
Message string `short:"m" required:"" help:"Checkin comment"`
Files []string `arg:"" optional:"" help:"Files to commit (default: all changes)"`
User string `help:"Checkin user (default: OS username)"`
Branch string `help:"Branch name for this checkin"`
AllowConflict bool `help:"Commit files that still hold merge conflict markers"`
AllowEmpty bool `help:"Commit even when nothing has changed"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoCiCmd.Run"></a>
### func \(\*RepoCiCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_ci.go#L23>)
```go
func (c *RepoCiCmd) Run(g *Globals) (err error)
```
<a name="RepoCloneCmd"></a>
## type [RepoCloneCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_clone.go#L13-L20>)
RepoCloneCmd clones a remote Fossil repository.
```go
type RepoCloneCmd struct {
URL string `arg:"" optional:"" help:"Remote Fossil server URL"`
Path string `arg:"" optional:"" help:"Local path for new repository file"`
User string `short:"u" help:"Username for clone auth"`
Pass string `short:"p" help:"Password for clone auth"`
Invite string `help:"Invite token (from fossil invite)"`
Timeout time.Duration `default:"10m" help:"Abort the clone if it runs longer than this; 0 disables the deadline"`
}
```
<a name="RepoCloneCmd.Run"></a>
### func \(\*RepoCloneCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_clone.go#L33>)
```go
func (c *RepoCloneCmd) Run(g *Globals) error
```
<a name="RepoCmd"></a>
## type [RepoCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo.go#L5-L46>)
RepoCmd is the top\-level command group for repository operations. Embed this in your CLI struct alongside Globals for a complete fossil CLI.
```go
type RepoCmd struct {
New RepoNewCmd `cmd:"" help:"Create a new repository"`
Clone RepoCloneCmd `cmd:"" help:"Clone a remote repository"`
Ci RepoCiCmd `cmd:"" help:"Checkin file changes"`
Co RepoCoCmd `cmd:"" help:"Checkout a version"`
Ls RepoLsCmd `cmd:"" help:"List files in a version"`
Timeline RepoTimelineCmd `cmd:"" help:"Show repository history"`
Cat RepoCatCmd `cmd:"" help:"Output artifact content"`
Info RepoInfoCmd `cmd:"" help:"Repository statistics"`
Hash RepoHashCmd `cmd:"" help:"Hash files (SHA1 or SHA3)"`
Delta RepoDeltaCmd `cmd:"" help:"Delta create/apply operations"`
Config RepoConfigCmd `cmd:"" help:"Repository configuration"`
Query RepoQueryCmd `cmd:"" help:"Execute SQL against repository"`
Verify RepoVerifyCmd `cmd:"" help:"Verify repository integrity"`
Resolve RepoResolveCmd `cmd:"" help:"Resolve symbolic name to UUID"`
Extract RepoExtractCmd `cmd:"" help:"Extract files from a version"`
Wiki RepoWikiCmd `cmd:"" help:"Wiki page operations"`
Tag RepoTagCmd `cmd:"" help:"Tag operations"`
Open RepoOpenCmd `cmd:"" help:"Open a checkout in a directory"`
Status RepoStatusCmd `cmd:"" help:"Show working directory changes"`
Add RepoAddCmd `cmd:"" help:"Stage files for addition"`
Rm RepoRmCmd `cmd:"" help:"Stage files for removal"`
Rename RepoRenameCmd `cmd:"" help:"Rename a tracked file"`
Revert RepoRevertCmd `cmd:"" help:"Undo staging changes"`
Diff RepoDiffCmd `cmd:"" help:"Show changes vs a version"`
Merge RepoMergeCmd `cmd:"" help:"Merge a divergent version"`
Conflicts RepoConflictsCmd `cmd:"" help:"List/manage unresolved conflicts"`
MarkResolved RepoMergeResolveCmd `cmd:"" name:"mark-resolved" help:"Mark a conflict as resolved"`
Undo RepoUndoCmd `cmd:"" help:"Undo last operation"`
Redo RepoRedoCmd `cmd:"" help:"Redo undone operation"`
Stash RepoStashCmd `cmd:"" help:"Stash working changes"`
Bisect RepoBisectCmd `cmd:"" help:"Binary search for bugs"`
Annotate RepoAnnotateCmd `cmd:"" help:"Annotate file lines with version history"`
Blame RepoBlameCmd `cmd:"" help:"Alias for annotate"`
Branch RepoBranchCmd `cmd:"" help:"Branch operations"`
UV RepoUVCmd `cmd:"" name:"uv" help:"Unversioned file operations"`
Schema RepoSchemaCmd `cmd:"" help:"Synced table schema operations"`
User RepoUserCmd `cmd:"" help:"User management"`
Invite RepoInviteCmd `cmd:"" help:"Generate invite token for a user"`
Serve RepoServeCmd `cmd:"" help:"Serve repository over HTTP for sync/clone"`
Submanifests RepoSubmanifestsCmd `cmd:"" help:"Sub-manifest tree settings"`
}
```
<a name="RepoCoCmd"></a>
## type [RepoCoCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_co.go#L12-L16>)
RepoCoCmd checks out a version to the working directory.
```go
type RepoCoCmd struct {
Version string `arg:"" optional:"" help:"Version to checkout (default: tip)"`
Dir string `short:"d" help:"Output directory (default: current dir)" default:"."`
Force bool `help:"Overwrite existing files"`
}
```
<a name="RepoCoCmd.Run"></a>
### func \(\*RepoCoCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_co.go#L18>)
```go
func (c *RepoCoCmd) Run(g *Globals) error
```
<a name="RepoConfigCmd"></a>
## type [RepoConfigCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L6-L10>)
RepoConfigCmd groups configuration operations.
```go
type RepoConfigCmd struct {
Ls RepoConfigLsCmd `cmd:"" help:"List all config entries"`
Get RepoConfigGetCmd `cmd:"" help:"Get a config value"`
Set RepoConfigSetCmd `cmd:"" help:"Set a config value"`
}
```
<a name="RepoConfigGetCmd"></a>
## type [RepoConfigGetCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L38-L40>)
RepoConfigGetCmd gets a single config value.
```go
type RepoConfigGetCmd struct {
Key string `arg:"" help:"Config key to get"`
}
```
<a name="RepoConfigGetCmd.Run"></a>
### func \(\*RepoConfigGetCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L42>)
```go
func (c *RepoConfigGetCmd) Run(g *Globals) error
```
<a name="RepoConfigLsCmd"></a>
## type [RepoConfigLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L13>)
RepoConfigLsCmd lists all config entries.
```go
type RepoConfigLsCmd struct{}
```
<a name="RepoConfigLsCmd.Run"></a>
### func \(\*RepoConfigLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L15>)
```go
func (c *RepoConfigLsCmd) Run(g *Globals) error
```
<a name="RepoConfigSetCmd"></a>
## type [RepoConfigSetCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L58-L61>)
RepoConfigSetCmd sets a config value.
```go
type RepoConfigSetCmd struct {
Key string `arg:"" help:"Config key"`
Value string `arg:"" help:"Config value"`
}
```
<a name="RepoConfigSetCmd.Run"></a>
### func \(\*RepoConfigSetCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_config.go#L63>)
```go
func (c *RepoConfigSetCmd) Run(g *Globals) error
```
<a name="RepoConflictsCmd"></a>
## type [RepoConflictsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L16-L23>)
RepoConflictsCmd groups conflict management operations.
```go
type RepoConflictsCmd struct {
Ls RepoConflictsLsCmd `cmd:"" default:"1" help:"List all conflicts"`
Show RepoConflictsShowCmd `cmd:"" help:"Show all versions of a conflicted file"`
Pick RepoConflictsPickCmd `cmd:"" help:"Resolve by picking one version"`
Merge RepoConflictsMergeCmd `cmd:"" help:"Resolve by re-merging with a different strategy"`
Extract RepoConflictsExtractCmd `cmd:"" help:"Extract all versions to disk for manual editing"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoConflictsExtractCmd"></a>
## type [RepoConflictsExtractCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L349-L352>)
RepoConflictsExtractCmd extracts all versions to disk for manual editing.
```go
type RepoConflictsExtractCmd struct {
File string `arg:"" help:"Conflicted file to extract"`
Dir string `short:"d" help:"Output directory" default:"."`
}
```
<a name="RepoConflictsExtractCmd.Run"></a>
### func \(\*RepoConflictsExtractCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L354>)
```go
func (c *RepoConflictsExtractCmd) Run(g *Globals) error
```
<a name="RepoConflictsLsCmd"></a>
## type [RepoConflictsLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L26>)
RepoConflictsLsCmd lists all conflicts.
```go
type RepoConflictsLsCmd struct{}
```
<a name="RepoConflictsLsCmd.Run"></a>
### func \(\*RepoConflictsLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L28>)
```go
func (c *RepoConflictsLsCmd) Run(g *Globals) error
```
<a name="RepoConflictsMergeCmd"></a>
## type [RepoConflictsMergeCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L277-L281>)
RepoConflictsMergeCmd resolves a conflict by re\-merging with a specified strategy.
```go
type RepoConflictsMergeCmd struct {
File string `arg:"" help:"Conflicted file to re-merge"`
Strategy string `help:"Strategy to use" default:"three-way"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoConflictsMergeCmd.Run"></a>
### func \(\*RepoConflictsMergeCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L283>)
```go
func (c *RepoConflictsMergeCmd) Run(g *Globals) error
```
<a name="RepoConflictsPickCmd"></a>
## type [RepoConflictsPickCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L218-L224>)
RepoConflictsPickCmd resolves a conflict by picking one version.
```go
type RepoConflictsPickCmd struct {
File string `arg:"" help:"Conflicted file to resolve"`
Local bool `help:"Keep local version" xor:"version"`
Remote bool `help:"Keep remote version" xor:"version"`
Base bool `help:"Revert to base version" xor:"version"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoConflictsPickCmd.Run"></a>
### func \(\*RepoConflictsPickCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L226>)
```go
func (c *RepoConflictsPickCmd) Run(g *Globals) error
```
<a name="RepoConflictsShowCmd"></a>
## type [RepoConflictsShowCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L159-L161>)
RepoConflictsShowCmd shows all versions of a conflicted file.
```go
type RepoConflictsShowCmd struct {
File string `arg:"" help:"Conflicted file to show"`
}
```
<a name="RepoConflictsShowCmd.Run"></a>
### func \(\*RepoConflictsShowCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_conflicts.go#L163>)
```go
func (c *RepoConflictsShowCmd) Run(g *Globals) error
```
<a name="RepoDeltaApplyCmd"></a>
## type [RepoDeltaApplyCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_delta.go#L46-L50>)
RepoDeltaApplyCmd applies a delta to a source file.
```go
type RepoDeltaApplyCmd struct {
Source string `arg:"" help:"Source (original) file"`
Delta string `arg:"" help:"Delta file"`
Output string `short:"o" help:"Output file (default: stdout)"`
}
```
<a name="RepoDeltaApplyCmd.Run"></a>
### func \(\*RepoDeltaApplyCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_delta.go#L52>)
```go
func (c *RepoDeltaApplyCmd) Run(g *Globals) error
```
<a name="RepoDeltaCmd"></a>
## type [RepoDeltaCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_delta.go#L11-L14>)
RepoDeltaCmd groups delta create/apply operations.
```go
type RepoDeltaCmd struct {
Create RepoDeltaCreateCmd `cmd:"" help:"Create a delta between two files"`
Apply RepoDeltaApplyCmd `cmd:"" help:"Apply a delta to a source file"`
}
```
<a name="RepoDeltaCreateCmd"></a>
## type [RepoDeltaCreateCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_delta.go#L17-L21>)
RepoDeltaCreateCmd creates a delta between two files.
```go
type RepoDeltaCreateCmd struct {
Source string `arg:"" help:"Source (original) file"`
Target string `arg:"" help:"Target (new) file"`
Output string `short:"o" help:"Output file (default: stdout)"`
}
```
<a name="RepoDeltaCreateCmd.Run"></a>
### func \(\*RepoDeltaCreateCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_delta.go#L23>)
```go
func (c *RepoDeltaCreateCmd) Run(g *Globals) error
```
<a name="RepoDiffCmd"></a>
## type [RepoDiffCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_diff.go#L15-L19>)
RepoDiffCmd shows changes in the working directory vs a repository version.
```go
type RepoDiffCmd struct {
Version string `arg:"" optional:"" help:"Version to diff against (default: tip)"`
Dir string `short:"d" help:"Working directory to compare" default:"."`
Unified int `short:"U" help:"Lines of context" default:"3"`
}
```
<a name="RepoDiffCmd.Run"></a>
### func \(\*RepoDiffCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_diff.go#L21>)
```go
func (c *RepoDiffCmd) Run(g *Globals) error
```
<a name="RepoExtractCmd"></a>
## type [RepoExtractCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_extract.go#L12-L16>)
RepoExtractCmd extracts files from a version.
```go
type RepoExtractCmd struct {
Version string `help:"Version to extract from (default: tip)"`
Files []string `arg:"" optional:"" help:"Files to extract (default: all)"`
Dir string `short:"d" help:"Output directory" default:"."`
}
```
<a name="RepoExtractCmd.Run"></a>
### func \(\*RepoExtractCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_extract.go#L18>)
```go
func (c *RepoExtractCmd) Run(g *Globals) error
```
<a name="RepoHashCmd"></a>
## type [RepoHashCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_hash.go#L11-L14>)
RepoHashCmd hashes files using SHA1 or SHA3\-256.
```go
type RepoHashCmd struct {
Files []string `arg:"" required:"" help:"Files to hash"`
SHA3 bool `name:"sha3" help:"Use SHA3-256 instead of SHA1"`
}
```
<a name="RepoHashCmd.Run"></a>
### func \(\*RepoHashCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_hash.go#L16>)
```go
func (c *RepoHashCmd) Run(g *Globals) error
```
<a name="RepoInfoCmd"></a>
## type [RepoInfoCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_info.go#L6>)
RepoInfoCmd shows repository statistics.
```go
type RepoInfoCmd struct{}
```
<a name="RepoInfoCmd.Run"></a>
### func \(\*RepoInfoCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_info.go#L8>)
```go
func (c *RepoInfoCmd) Run(g *Globals) error
```
<a name="RepoInviteCmd"></a>
## type [RepoInviteCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_invite.go#L12-L17>)
RepoInviteCmd generates an invite token for a new user.
```go
type RepoInviteCmd struct {
Login string `arg:"" help:"Username for the invitee"`
Cap string `help:"Capability string (e.g. oi)" required:""`
URL string `help:"Sync URL to embed in token" default:""`
TTL time.Duration `help:"Token time-to-live (e.g. 24h)" default:"0"`
}
```
<a name="RepoInviteCmd.Run"></a>
### func \(\*RepoInviteCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_invite.go#L19>)
```go
func (c *RepoInviteCmd) Run(g *Globals) error
```
<a name="RepoLsCmd"></a>
## type [RepoLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_ls.go#L6-L9>)
RepoLsCmd lists files in a version.
```go
type RepoLsCmd struct {
Version string `arg:"" optional:"" help:"Version to list (default: tip)"`
Long bool `short:"l" help:"Show sizes and hashes"`
}
```
<a name="RepoLsCmd.Run"></a>
### func \(\*RepoLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_ls.go#L11>)
```go
func (c *RepoLsCmd) Run(g *Globals) error
```
<a name="RepoMergeCmd"></a>
## type [RepoMergeCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_merge.go#L10-L15>)
RepoMergeCmd merges a divergent version into the current checkout.
```go
type RepoMergeCmd struct {
Version string `arg:"" help:"Version to merge into current checkout"`
Strategy string `help:"Override merge strategy for all files"`
DryRun bool `help:"Show what would be merged without writing"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoMergeCmd.Run"></a>
### func \(\*RepoMergeCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_merge.go#L17>)
```go
func (c *RepoMergeCmd) Run(g *Globals) (err error)
```
<a name="RepoMergeResolveCmd"></a>
## type [RepoMergeResolveCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_merge_resolve.go#L14-L17>)
RepoMergeResolveCmd marks a file conflict as resolved.
A merge conflict needs no marking: as in fossil, a file is in conflict while it holds conflict markers, and editing them out resolves it. So this command refuses a file that still holds markers, and resolves the conflict\-fork entries the conflict\-fork strategy records.
```go
type RepoMergeResolveCmd struct {
File string `arg:"" help:"File to mark as resolved"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoMergeResolveCmd.Run"></a>
### func \(\*RepoMergeResolveCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_merge_resolve.go#L19>)
```go
func (c *RepoMergeResolveCmd) Run(g *Globals) (err error)
```
<a name="RepoNewCmd"></a>
## type [RepoNewCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_new.go#L10-L13>)
RepoNewCmd creates a new Fossil repository.
```go
type RepoNewCmd struct {
Path string `arg:"" help:"Path for new repository file"`
User string `help:"Default user name" default:""`
}
```
<a name="RepoNewCmd.Run"></a>
### func \(\*RepoNewCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_new.go#L15>)
```go
func (c *RepoNewCmd) Run(g *Globals) error
```
<a name="RepoOpenCmd"></a>
## type [RepoOpenCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_open.go#L12-L14>)
RepoOpenCmd opens a checkout in a directory, creating the .fslckout database.
```go
type RepoOpenCmd struct {
Dir string `arg:"" optional:"" help:"Checkout directory (default: current dir)" default:"."`
}
```
<a name="RepoOpenCmd.Run"></a>
### func \(\*RepoOpenCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_open.go#L16>)
```go
func (c *RepoOpenCmd) Run(g *Globals) error
```
<a name="RepoQueryCmd"></a>
## type [RepoQueryCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_query.go#L9-L11>)
RepoQueryCmd executes raw SQL against the repository database.
```go
type RepoQueryCmd struct {
SQL string `arg:"" help:"SQL query to execute"`
}
```
<a name="RepoQueryCmd.Run"></a>
### func \(\*RepoQueryCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_query.go#L13>)
```go
func (c *RepoQueryCmd) Run(g *Globals) error
```
<a name="RepoRedoCmd"></a>
## type [RepoRedoCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_undo.go#L18-L20>)
RepoRedoCmd re\-applies the last undone operation.
```go
type RepoRedoCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoRedoCmd.Run"></a>
### func \(\*RepoRedoCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_undo.go#L22>)
```go
func (c *RepoRedoCmd) Run(g *Globals) error
```
<a name="RepoRenameCmd"></a>
## type [RepoRenameCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_rename.go#L6-L10>)
RepoRenameCmd renames a tracked file in the checkout and on disk.
```go
type RepoRenameCmd struct {
From string `arg:"" help:"Current file name"`
To string `arg:"" help:"New file name"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoRenameCmd.Run"></a>
### func \(\*RepoRenameCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_rename.go#L12>)
```go
func (c *RepoRenameCmd) Run(g *Globals) (err error)
```
<a name="RepoResolveCmd"></a>
## type [RepoResolveCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_resolve.go#L6-L8>)
RepoResolveCmd resolves a symbolic name to UUID and RID.
```go
type RepoResolveCmd struct {
Name string `arg:"" help:"Symbolic name, UUID, or prefix to resolve (e.g. trunk, tip, UUID prefix)"`
}
```
<a name="RepoResolveCmd.Run"></a>
### func \(\*RepoResolveCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_resolve.go#L10>)
```go
func (c *RepoResolveCmd) Run(g *Globals) error
```
<a name="RepoRevertCmd"></a>
## type [RepoRevertCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_revert.go#L10-L13>)
RepoRevertCmd restores files to their checked\-out version.
```go
type RepoRevertCmd struct {
Files []string `arg:"" optional:"" help:"Files to revert (default: all)"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoRevertCmd.Run"></a>
### func \(\*RepoRevertCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_revert.go#L15>)
```go
func (c *RepoRevertCmd) Run(g *Globals) (err error)
```
<a name="RepoRmCmd"></a>
## type [RepoRmCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_rm.go#L6-L9>)
RepoRmCmd stages files for removal from the checkout.
```go
type RepoRmCmd struct {
Files []string `arg:"" required:"" help:"Files to stage for removal"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoRmCmd.Run"></a>
### func \(\*RepoRmCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_rm.go#L11>)
```go
func (c *RepoRmCmd) Run(g *Globals) (err error)
```
<a name="RepoSchemaAddCmd"></a>
## type [RepoSchemaAddCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L22-L26>)
RepoSchemaAddCmd registers a new synced table.
```go
type RepoSchemaAddCmd struct {
Name string `arg:"" help:"Table name (without x_ prefix)"`
Columns string `required:"" help:"Column defs: name:type[:pk],... (e.g. peer_id:text:pk,addr:text)"`
Conflict string `default:"mtime-wins" enum:"self-write,mtime-wins,owner-write" help:"Conflict strategy"`
}
```
<a name="RepoSchemaAddCmd.Run"></a>
### func \(\*RepoSchemaAddCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L28>)
```go
func (c *RepoSchemaAddCmd) Run(g *Globals) error
```
<a name="RepoSchemaCmd"></a>
## type [RepoSchemaCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L14-L19>)
RepoSchemaCmd groups synced table schema operations.
```go
type RepoSchemaCmd struct {
Add RepoSchemaAddCmd `cmd:"" help:"Register a new synced table"`
List RepoSchemaListCmd `cmd:"" help:"List registered synced tables"`
Show RepoSchemaShowCmd `cmd:"" help:"Show table schema details"`
Remove RepoSchemaRemoveCmd `cmd:"" help:"Remove a synced table registration"`
}
```
<a name="RepoSchemaListCmd"></a>
## type [RepoSchemaListCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L60>)
RepoSchemaListCmd lists registered synced tables.
```go
type RepoSchemaListCmd struct{}
```
<a name="RepoSchemaListCmd.Run"></a>
### func \(\*RepoSchemaListCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L62>)
```go
func (c *RepoSchemaListCmd) Run(g *Globals) error
```
<a name="RepoSchemaRemoveCmd"></a>
## type [RepoSchemaRemoveCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L133-L135>)
RepoSchemaRemoveCmd removes a synced table registration.
```go
type RepoSchemaRemoveCmd struct {
Name string `arg:"" help:"Table name (without x_ prefix)"`
}
```
<a name="RepoSchemaRemoveCmd.Run"></a>
### func \(\*RepoSchemaRemoveCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L137>)
```go
func (c *RepoSchemaRemoveCmd) Run(g *Globals) error
```
<a name="RepoSchemaShowCmd"></a>
## type [RepoSchemaShowCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L93-L95>)
RepoSchemaShowCmd shows table schema details.
```go
type RepoSchemaShowCmd struct {
Name string `arg:"" help:"Table name (without x_ prefix)"`
}
```
<a name="RepoSchemaShowCmd.Run"></a>
### func \(\*RepoSchemaShowCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_schema.go#L97>)
```go
func (c *RepoSchemaShowCmd) Run(g *Globals) error
```
<a name="RepoServeCmd"></a>
## type [RepoServeCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_serve.go#L19-L21>)
RepoServeCmd starts an HTTP xfer server for the repository so a remote fossil client \-\- the canonical binary or another instance of this tool \-\- can clone or sync against it. This is a thin wrapper: all serving logic lives in Repo.ServeHTTP; the command's job is to open the repo, resolve the bind address, and translate process interrupt into the context cancellation that ServeHTTP already honors. Access follows the user table, as with fossil serve: clients without credentials act as nobody, which may clone and pull a new repository but not push to it.
```go
type RepoServeCmd struct {
Addr string `short:"P" default:"127.0.0.1:8080" help:"Bind address as host:port"`
}
```
<a name="RepoServeCmd.Run"></a>
### func \(\*RepoServeCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_serve.go#L23>)
```go
func (c *RepoServeCmd) Run(g *Globals) error
```
<a name="RepoStashApplyCmd"></a>
## type [RepoStashApplyCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L45-L48>)
RepoStashApplyCmd applies a stash entry without removing it.
```go
type RepoStashApplyCmd struct {
ID int64 `arg:"" optional:"" help:"Stash ID to apply (default: latest)"`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoStashApplyCmd.Run"></a>
### func \(\*RepoStashApplyCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L50>)
```go
func (c *RepoStashApplyCmd) Run(g *Globals) error
```
<a name="RepoStashClearCmd"></a>
## type [RepoStashClearCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L98>)
RepoStashClearCmd removes all stash entries.
```go
type RepoStashClearCmd struct{}
```
<a name="RepoStashClearCmd.Run"></a>
### func \(\*RepoStashClearCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L100>)
```go
func (c *RepoStashClearCmd) Run(g *Globals) error
```
<a name="RepoStashCmd"></a>
## type [RepoStashCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L6-L13>)
RepoStashCmd groups stash operations.
```go
type RepoStashCmd struct {
Save RepoStashSaveCmd `cmd:"" help:"Stash working changes"`
Pop RepoStashPopCmd `cmd:"" help:"Apply top stash and drop it"`
Apply RepoStashApplyCmd `cmd:"" help:"Apply stash without dropping"`
Ls RepoStashLsCmd `cmd:"" help:"List stash entries"`
Drop RepoStashDropCmd `cmd:"" help:"Remove stash entry"`
Clear RepoStashClearCmd `cmd:"" help:"Remove all stash entries"`
}
```
<a name="RepoStashDropCmd"></a>
## type [RepoStashDropCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L84-L86>)
RepoStashDropCmd removes a stash entry by ID.
```go
type RepoStashDropCmd struct {
ID int64 `arg:"" required:"" help:"Stash ID to drop"`
}
```
<a name="RepoStashDropCmd.Run"></a>
### func \(\*RepoStashDropCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L88>)
```go
func (c *RepoStashDropCmd) Run(g *Globals) error
```
<a name="RepoStashLsCmd"></a>
## type [RepoStashLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L60>)
RepoStashLsCmd lists stash entries.
```go
type RepoStashLsCmd struct{}
```
<a name="RepoStashLsCmd.Run"></a>
### func \(\*RepoStashLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L62>)
```go
func (c *RepoStashLsCmd) Run(g *Globals) error
```
<a name="RepoStashPopCmd"></a>
## type [RepoStashPopCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L31-L33>)
RepoStashPopCmd pops the top stash entry.
```go
type RepoStashPopCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoStashPopCmd.Run"></a>
### func \(\*RepoStashPopCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L35>)
```go
func (c *RepoStashPopCmd) Run(g *Globals) error
```
<a name="RepoStashSaveCmd"></a>
## type [RepoStashSaveCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L16-L19>)
RepoStashSaveCmd saves working changes to the stash.
```go
type RepoStashSaveCmd struct {
Message string `short:"m" help:"Stash message" default:""`
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoStashSaveCmd.Run"></a>
### func \(\*RepoStashSaveCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_stash.go#L21>)
```go
func (c *RepoStashSaveCmd) Run(g *Globals) error
```
<a name="RepoStatusCmd"></a>
## type [RepoStatusCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_status.go#L16-L18>)
RepoStatusCmd shows working directory changes vs the tip version.
```go
type RepoStatusCmd struct {
Dir string `short:"d" help:"Checkout directory to scan" default:"."`
}
```
<a name="RepoStatusCmd.Run"></a>
### func \(\*RepoStatusCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_status.go#L20>)
```go
func (c *RepoStatusCmd) Run(g *Globals) error
```
<a name="RepoSubmanifestsCmd"></a>
## type [RepoSubmanifestsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L14-L19>)
RepoSubmanifestsCmd groups the sub\-manifest settings \(draft\-fossil\-submanifests\-00\): whether new check\-ins are written as trees, and the partition parameter k they are built with.
```go
type RepoSubmanifestsCmd struct {
Enable RepoSubmanifestsEnableCmd `cmd:"" help:"Write new check-ins as sub-manifest trees"`
Retune RepoSubmanifestsRetuneCmd `cmd:"" help:"Re-pin the partition parameter for later commits"`
Disable RepoSubmanifestsDisableCmd `cmd:"" help:"Write new check-ins as flat manifests again"`
Status RepoSubmanifestsStatusCmd `cmd:"" help:"Show the sub-manifest settings and whether trees exist"`
}
```
<a name="RepoSubmanifestsDisableCmd"></a>
## type [RepoSubmanifestsDisableCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L75>)
RepoSubmanifestsDisableCmd turns tree emission off; existing trees stay.
```go
type RepoSubmanifestsDisableCmd struct{}
```
<a name="RepoSubmanifestsDisableCmd.Run"></a>
### func \(\*RepoSubmanifestsDisableCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L77>)
```go
func (c *RepoSubmanifestsDisableCmd) Run(g *Globals) error
```
<a name="RepoSubmanifestsEnableCmd"></a>
## type [RepoSubmanifestsEnableCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L22-L24>)
RepoSubmanifestsEnableCmd turns tree emission on, pinning k the first time.
```go
type RepoSubmanifestsEnableCmd struct {
K *int `name:"k" help:"Partition parameter, 1..12 (default: selected from the main-branch tip)"`
}
```
<a name="RepoSubmanifestsEnableCmd.Run"></a>
### func \(\*RepoSubmanifestsEnableCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L26>)
```go
func (c *RepoSubmanifestsEnableCmd) Run(g *Globals) error
```
<a name="RepoSubmanifestsRetuneCmd"></a>
## type [RepoSubmanifestsRetuneCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L54-L56>)
RepoSubmanifestsRetuneCmd re\-pins k; a re\-tune is always explicit.
```go
type RepoSubmanifestsRetuneCmd struct {
K int `name:"k" required:"" help:"New partition parameter, 1..12"`
}
```
<a name="RepoSubmanifestsRetuneCmd.Run"></a>
### func \(\*RepoSubmanifestsRetuneCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L58>)
```go
func (c *RepoSubmanifestsRetuneCmd) Run(g *Globals) error
```
<a name="RepoSubmanifestsStatusCmd"></a>
## type [RepoSubmanifestsStatusCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L100>)
RepoSubmanifestsStatusCmd prints the three settings and whether the repository holds any S\-bearing artifact.
```go
type RepoSubmanifestsStatusCmd struct{}
```
<a name="RepoSubmanifestsStatusCmd.Run"></a>
### func \(\*RepoSubmanifestsStatusCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_submanifests.go#L102>)
```go
func (c *RepoSubmanifestsStatusCmd) Run(g *Globals) error
```
<a name="RepoTagAddCmd"></a>
## type [RepoTagAddCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_tag.go#L60-L64>)
RepoTagAddCmd adds a tag to an artifact.
```go
type RepoTagAddCmd struct {
Tag string `arg:"" help:"Tag name"`
Value string `arg:"" optional:"" help:"Tag value (optional)"`
Version string `help:"Version to tag (default: tip)"`
}
```
<a name="RepoTagAddCmd.Run"></a>
### func \(\*RepoTagAddCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_tag.go#L66>)
```go
func (c *RepoTagAddCmd) Run(g *Globals) error
```
<a name="RepoTagCmd"></a>
## type [RepoTagCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_tag.go#L9-L12>)
RepoTagCmd groups tag operations.
```go
type RepoTagCmd struct {
Ls RepoTagLsCmd `cmd:"" help:"List tags on an artifact"`
Add RepoTagAddCmd `cmd:"" help:"Add a tag to an artifact"`
}
```
<a name="RepoTagLsCmd"></a>
## type [RepoTagLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_tag.go#L15-L17>)
RepoTagLsCmd lists tags on an artifact.
```go
type RepoTagLsCmd struct {
Version string `arg:"" optional:"" help:"Version to list tags for (default: tip)"`
}
```
<a name="RepoTagLsCmd.Run"></a>
### func \(\*RepoTagLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_tag.go#L19>)
```go
func (c *RepoTagLsCmd) Run(g *Globals) error
```
<a name="RepoTimelineCmd"></a>
## type [RepoTimelineCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_timeline.go#L10-L12>)
RepoTimelineCmd shows repository timeline/history.
```go
type RepoTimelineCmd struct {
Limit int `short:"n" default:"20" help:"Number of entries"`
}
```
<a name="RepoTimelineCmd.Run"></a>
### func \(\*RepoTimelineCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_timeline.go#L14>)
```go
func (c *RepoTimelineCmd) Run(g *Globals) error
```
<a name="RepoUVCmd"></a>
## type [RepoUVCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L10-L15>)
RepoUVCmd groups unversioned file operations.
```go
type RepoUVCmd struct {
Ls RepoUVLsCmd `cmd:"" help:"List unversioned files"`
Put RepoUVPutCmd `cmd:"" help:"Add or update an unversioned file"`
Get RepoUVGetCmd `cmd:"" help:"Retrieve an unversioned file"`
Delete RepoUVDeleteCmd `cmd:"" help:"Delete an unversioned file (creates tombstone)"`
}
```
<a name="RepoUVDeleteCmd"></a>
## type [RepoUVDeleteCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L110-L112>)
RepoUVDeleteCmd deletes an unversioned file \(creates a tombstone\).
```go
type RepoUVDeleteCmd struct {
Name string `arg:"" help:"Name of the unversioned file to delete"`
}
```
<a name="RepoUVDeleteCmd.Run"></a>
### func \(\*RepoUVDeleteCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L114>)
```go
func (c *RepoUVDeleteCmd) Run(g *Globals) error
```
<a name="RepoUVGetCmd"></a>
## type [RepoUVGetCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L79-L82>)
RepoUVGetCmd retrieves an unversioned file.
```go
type RepoUVGetCmd struct {
Name string `arg:"" help:"Name of the unversioned file"`
Output string `short:"o" help:"Output file (default: stdout)"`
}
```
<a name="RepoUVGetCmd.Run"></a>
### func \(\*RepoUVGetCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L84>)
```go
func (c *RepoUVGetCmd) Run(g *Globals) error
```
<a name="RepoUVLsCmd"></a>
## type [RepoUVLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L18>)
RepoUVLsCmd lists unversioned files.
```go
type RepoUVLsCmd struct{}
```
<a name="RepoUVLsCmd.Run"></a>
### func \(\*RepoUVLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L20>)
```go
func (c *RepoUVLsCmd) Run(g *Globals) error
```
<a name="RepoUVPutCmd"></a>
## type [RepoUVPutCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L53-L56>)
RepoUVPutCmd adds or updates an unversioned file.
```go
type RepoUVPutCmd struct {
Name string `arg:"" help:"Name of the unversioned file"`
File string `arg:"" help:"Local file to upload"`
}
```
<a name="RepoUVPutCmd.Run"></a>
### func \(\*RepoUVPutCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_uv.go#L58>)
```go
func (c *RepoUVPutCmd) Run(g *Globals) error
```
<a name="RepoUndoCmd"></a>
## type [RepoUndoCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_undo.go#L4-L6>)
RepoUndoCmd undoes the last checkout operation.
```go
type RepoUndoCmd struct {
Dir string `short:"d" help:"Checkout directory" default:"."`
}
```
<a name="RepoUndoCmd.Run"></a>
### func \(\*RepoUndoCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_undo.go#L8>)
```go
func (c *RepoUndoCmd) Run(g *Globals) error
```
<a name="RepoUserCmd"></a>
## type [RepoUserCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L12-L18>)
RepoUserCmd groups user management operations.
```go
type RepoUserCmd struct {
Add UserAddCmd `cmd:"" help:"Create a new user"`
List UserListCmd `cmd:"" help:"List all users"`
Update UserUpdateCmd `cmd:"" help:"Update user capabilities"`
Rm UserRmCmd `cmd:"" help:"Delete a user"`
Passwd UserPasswdCmd `cmd:"" help:"Reset user password"`
}
```
<a name="RepoVerifyCmd"></a>
## type [RepoVerifyCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_verify.go#L6>)
RepoVerifyCmd verifies repository integrity.
```go
type RepoVerifyCmd struct{}
```
<a name="RepoVerifyCmd.Run"></a>
### func \(\*RepoVerifyCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_verify.go#L8>)
```go
func (c *RepoVerifyCmd) Run(g *Globals) error
```
<a name="RepoWikiCmd"></a>
## type [RepoWikiCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_wiki.go#L13-L16>)
RepoWikiCmd groups wiki operations.
```go
type RepoWikiCmd struct {
Ls RepoWikiLsCmd `cmd:"" help:"List wiki pages"`
Export RepoWikiExportCmd `cmd:"" help:"Export a wiki page"`
}
```
<a name="RepoWikiExportCmd"></a>
## type [RepoWikiExportCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_wiki.go#L60-L63>)
RepoWikiExportCmd exports a wiki page.
```go
type RepoWikiExportCmd struct {
Page string `arg:"" help:"Wiki page name or artifact UUID"`
Output string `short:"o" help:"Output file (default: stdout)"`
}
```
<a name="RepoWikiExportCmd.Run"></a>
### func \(\*RepoWikiExportCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_wiki.go#L65>)
```go
func (c *RepoWikiExportCmd) Run(g *Globals) error
```
<a name="RepoWikiLsCmd"></a>
## type [RepoWikiLsCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_wiki.go#L19>)
RepoWikiLsCmd lists wiki pages.
```go
type RepoWikiLsCmd struct{}
```
<a name="RepoWikiLsCmd.Run"></a>
### func \(\*RepoWikiLsCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_wiki.go#L21>)
```go
func (c *RepoWikiLsCmd) Run(g *Globals) error
```
<a name="UserAddCmd"></a>
## type [UserAddCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L21-L24>)
UserAddCmd creates a new user.
```go
type UserAddCmd struct {
Login string `arg:"" help:"Username"`
Cap string `help:"Capability string (e.g. oi)" required:""`
}
```
<a name="UserAddCmd.Run"></a>
### func \(\*UserAddCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L26>)
```go
func (c *UserAddCmd) Run(g *Globals) error
```
<a name="UserListCmd"></a>
## type [UserListCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L51>)
UserListCmd lists all users.
```go
type UserListCmd struct{}
```
<a name="UserListCmd.Run"></a>
### func \(\*UserListCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L53>)
```go
func (c *UserListCmd) Run(g *Globals) error
```
<a name="UserPasswdCmd"></a>
## type [UserPasswdCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L111-L113>)
UserPasswdCmd resets a user's password.
```go
type UserPasswdCmd struct {
Login string `arg:"" help:"Username"`
}
```
<a name="UserPasswdCmd.Run"></a>
### func \(\*UserPasswdCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L115>)
```go
func (c *UserPasswdCmd) Run(g *Globals) error
```
<a name="UserRmCmd"></a>
## type [UserRmCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L92-L94>)
UserRmCmd deletes a user.
```go
type UserRmCmd struct {
Login string `arg:"" help:"Username"`
}
```
<a name="UserRmCmd.Run"></a>
### func \(\*UserRmCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L96>)
```go
func (c *UserRmCmd) Run(g *Globals) error
```
<a name="UserUpdateCmd"></a>
## type [UserUpdateCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L72-L75>)
UserUpdateCmd updates user capabilities.
```go
type UserUpdateCmd struct {
Login string `arg:"" help:"Username"`
Cap string `help:"New capability string" required:""`
}
```
<a name="UserUpdateCmd.Run"></a>
### func \(\*UserUpdateCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/repo_user.go#L77>)
```go
func (c *UserUpdateCmd) Run(g *Globals) error
```
<a name="VersionCmd"></a>
## type [VersionCmd](<https://github.com/danmestas/go-libfossil/blob/main/cli/version.go#L52>)
VersionCmd prints a single\-line, stable, machine\-parseable build identifier and exits 0.
```go
type VersionCmd struct{}
```
<a name="VersionCmd.Run"></a>
### func \(\*VersionCmd\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/cli/version.go#L56>)
```go
func (c *VersionCmd) Run() error
```
Run prints Version\(\) and always succeeds: there is nothing about the local environment that can make reporting the build identifier fail.
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
---
# db/driver/modernc
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/db/driver/modernc/
Pure-Go SQLite driver, the libfossil default.
```go
import _ "github.com/danmestas/go-libfossil/db/driver/modernc"
```
Importing this package registers a `modernc.org/sqlite` driver (driver name `"sqlite"`) with libfossil's `db` registry. The package exports no public API of its own — register-on-import is the contract.
Use this driver when you want a static, CGo-free build with no native dependencies.
See [db](/docs/reference/sdk/db/api/) for the registry interface.
---
# db/driver/ncruces
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/db/driver/ncruces/
Wasm-friendly SQLite driver based on `ncruces/go-sqlite3`.
```go
import _ "github.com/danmestas/go-libfossil/db/driver/ncruces"
```
Importing this package registers an `ncruces` driver (driver name `"sqlite3"`) with libfossil's `db` registry. The package exports no public API of its own — register-on-import is the contract.
On `js/wasm` targets the package additionally imports `go-sqlite3-opfs`, routing the OPFS virtual filesystem through the same driver registration so browser-side builds get persistent storage automatically.
Use this driver when you need a smaller Wasm footprint than `modernc` provides, or for build configurations where `ncruces`'s tradeoffs are preferred.
See [db](/docs/reference/sdk/db/api/) for the registry interface.
---
# db
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/db/api/
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# db
```go
import "github.com/danmestas/go-libfossil/db"
```
Package db provides a SQLite database layer with pluggable drivers.
Two SQLite drivers ship with libfossil — modernc \(pure Go, default\) and ncruces \(WASM\-capable\). Select one at build time by importing its driver package:
```
import _ "github.com/danmestas/go-libfossil/db/driver/modernc"
```
[Open](<#Open>) and [OpenWith](<#OpenWith>) handle DSN construction, WAL/pragma setup, and WASM\-specific workarounds. Use [DB.WithTx](<#DB.WithTx>) for transaction scoping with automatic rollback on error.
The [Querier](<#Querier>) interface \(Exec, QueryRow, Query\) is satisfied by both [DB](<#DB>) and [Tx](<#Tx>), allowing callers to write transaction\-agnostic code.
## Index
- [func CreateRepoSchema\(d \*DB\) error](<#CreateRepoSchema>)
- [func DefaultPragmas\(\) map\[string\]string](<#DefaultPragmas>)
- [func OpenSQL\(path string, cfg OpenConfig, params map\[string\]string\) \(\*sql.DB, error\)](<#OpenSQL>)
- [func Register\(cfg DriverConfig\)](<#Register>)
- [func SQLDriverAndDSN\(path string, cfg OpenConfig, params map\[string\]string\) \(string, string\)](<#SQLDriverAndDSN>)
- [func ScanInt\(v any\) \(int, bool\)](<#ScanInt>)
- [func ScanJulianDay\(v any\) \(float64, bool\)](<#ScanJulianDay>)
- [func ScanTime\(v any\) \(time.Time, bool\)](<#ScanTime>)
- [func SeedConfig\(d \*DB, rng simio.Rand, projectCode string\) error](<#SeedConfig>)
- [func SeedNobody\(d \*DB, caps string\) error](<#SeedNobody>)
- [func SeedUser\(d \*DB, login string\) error](<#SeedUser>)
- [type CheckpointMode](<#CheckpointMode>)
- [func \(m CheckpointMode\) String\(\) string](<#CheckpointMode.String>)
- [type DB](<#DB>)
- [func Open\(path string\) \(\*DB, error\)](<#Open>)
- [func OpenWith\(path string, cfg OpenConfig\) \(\*DB, error\)](<#OpenWith>)
- [func \(d \*DB\) ApplicationID\(\) \(int32, error\)](<#DB.ApplicationID>)
- [func \(d \*DB\) Checkpoint\(mode CheckpointMode\) error](<#DB.Checkpoint>)
- [func \(d \*DB\) Close\(\) error](<#DB.Close>)
- [func \(d \*DB\) Driver\(\) string](<#DB.Driver>)
- [func \(d \*DB\) Exec\(query string, args ...any\) \(sql.Result, error\)](<#DB.Exec>)
- [func \(d \*DB\) Path\(\) string](<#DB.Path>)
- [func \(d \*DB\) Query\(query string, args ...any\) \(\*sql.Rows, error\)](<#DB.Query>)
- [func \(d \*DB\) QueryRow\(query string, args ...any\) \*sql.Row](<#DB.QueryRow>)
- [func \(d \*DB\) SetApplicationID\(id int32\) error](<#DB.SetApplicationID>)
- [func \(d \*DB\) SqlDB\(\) \*sql.DB](<#DB.SqlDB>)
- [func \(d \*DB\) WithTx\(fn func\(tx \*Tx\) error\) error](<#DB.WithTx>)
- [type DriverConfig](<#DriverConfig>)
- [func RegisteredDriver\(\) \*DriverConfig](<#RegisteredDriver>)
- [type OpenConfig](<#OpenConfig>)
- [type Querier](<#Querier>)
- [type Tx](<#Tx>)
- [func \(t \*Tx\) Exec\(query string, args ...any\) \(sql.Result, error\)](<#Tx.Exec>)
- [func \(t \*Tx\) Query\(query string, args ...any\) \(\*sql.Rows, error\)](<#Tx.Query>)
- [func \(t \*Tx\) QueryRow\(query string, args ...any\) \*sql.Row](<#Tx.QueryRow>)
<a name="CreateRepoSchema"></a>
## func [CreateRepoSchema](<https://github.com/danmestas/go-libfossil/blob/main/db/schema.go#L220>)
```go
func CreateRepoSchema(d *DB) error
```
<a name="DefaultPragmas"></a>
## func [DefaultPragmas](<https://github.com/danmestas/go-libfossil/blob/main/db/config.go#L10>)
```go
func DefaultPragmas() map[string]string
```
DefaultPragmas returns the default pragma settings.
<a name="OpenSQL"></a>
## func [OpenSQL](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L60>)
```go
func OpenSQL(path string, cfg OpenConfig, params map[string]string) (*sql.DB, error)
```
OpenSQL opens a raw \*sql.DB using the registered driver and the same DSN construction as OpenWith. params are appended as URI query parameters after driver pragmas, so callers can request options such as mode=ro without constructing driver\-specific DSNs.
<a name="Register"></a>
## func [Register](<https://github.com/danmestas/go-libfossil/blob/main/db/register.go#L14>)
```go
func Register(cfg DriverConfig)
```
Register registers a SQLite driver for use by Open/OpenWith. Must be called exactly once \(typically from a driver package's init\(\)\). Panics if called more than once.
<a name="SQLDriverAndDSN"></a>
## func [SQLDriverAndDSN](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L75>)
```go
func SQLDriverAndDSN(path string, cfg OpenConfig, params map[string]string) (string, string)
```
SQLDriverAndDSN returns the driver name and DSN OpenWith would use, with optional URI query params appended after driver\-specific options.
<a name="ScanInt"></a>
## func [ScanInt](<https://github.com/danmestas/go-libfossil/blob/main/db/scan.go#L43>)
```go
func ScanInt(v any) (int, bool)
```
ScanInt converts a scanned value to int. SQLite drivers differ on BOOLEAN columns: modernc returns int64, ncruces returns bool. Scan the column into an \`any\` variable, then pass it here.
<a name="ScanJulianDay"></a>
## func [ScanJulianDay](<https://github.com/danmestas/go-libfossil/blob/main/db/scan.go#L12>)
```go
func ScanJulianDay(v any) (float64, bool)
```
ScanJulianDay converts a scanned mtime value to a float64 Julian Day Number. SQLite drivers return mtime differently: modernc returns float64, ncruces returns time.Time for DATETIME/TIMESTAMP/DATE columns. Scan the column into an \`any\` variable, then pass it here.
<a name="ScanTime"></a>
## func [ScanTime](<https://github.com/danmestas/go-libfossil/blob/main/db/scan.go#L27>)
```go
func ScanTime(v any) (time.Time, bool)
```
ScanTime converts a scanned mtime value to time.Time. Same driver\-compatibility rationale as ScanJulianDay.
<a name="SeedConfig"></a>
## func [SeedConfig](<https://github.com/danmestas/go-libfossil/blob/main/db/schema.go#L267>)
```go
func SeedConfig(d *DB, rng simio.Rand, projectCode string) error
```
SeedConfig seeds the config table with project\-code, server\-code, and schema markers. If projectCode is empty, a fresh 40\-char lowercase\-hex project\-code is generated from rng. If non\-empty, it must match ^\[0\-9a\-f\]\{40\}$; otherwise an error is returned and no rows are written. Server\-code is always generated.
<a name="SeedNobody"></a>
## func [SeedNobody](<https://github.com/danmestas/go-libfossil/blob/main/db/schema.go#L251>)
```go
func SeedNobody(d *DB, caps string) error
```
SeedNobody inserts a "nobody" user with the given capabilities. This controls anonymous access policy for the repo.
<a name="SeedUser"></a>
## func [SeedUser](<https://github.com/danmestas/go-libfossil/blob/main/db/schema.go#L235>)
```go
func SeedUser(d *DB, login string) error
```
<a name="CheckpointMode"></a>
## type [CheckpointMode](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L14>)
CheckpointMode mirrors SQLite's PRAGMA wal\_checkpoint\(\<mode\>\) argument.
```go
type CheckpointMode int
```
<a name="CheckpointPassive"></a>
```go
const (
// CheckpointPassive checkpoints frames not held by readers; never blocks.
// Appropriate for periodic background checkpoints.
CheckpointPassive CheckpointMode = iota
// CheckpointFull blocks new writers until all frames are checkpointed.
CheckpointFull
// CheckpointRestart is FULL plus restarts the WAL file.
CheckpointRestart
// CheckpointTruncate is RESTART plus truncates the WAL file to zero bytes.
// Produces the most compact on-disk file and is what Close uses.
CheckpointTruncate
)
```
<a name="CheckpointMode.String"></a>
### func \(CheckpointMode\) [String](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L29>)
```go
func (m CheckpointMode) String() string
```
<a name="DB"></a>
## type [DB](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L45-L49>)
DB wraps a SQLite database connection.
```go
type DB struct {
// contains filtered or unexported fields
}
```
<a name="Open"></a>
### func [Open](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L52>)
```go
func Open(path string) (*DB, error)
```
Open opens a SQLite database with the registered driver and default pragmas.
<a name="OpenWith"></a>
### func [OpenWith](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L178>)
```go
func OpenWith(path string, cfg OpenConfig) (*DB, error)
```
OpenWith opens a SQLite database with explicit configuration.
<a name="DB.ApplicationID"></a>
### func \(\*DB\) [ApplicationID](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L263>)
```go
func (d *DB) ApplicationID() (int32, error)
```
<a name="DB.Checkpoint"></a>
### func \(\*DB\) [Checkpoint](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L223>)
```go
func (d *DB) Checkpoint(mode CheckpointMode) error
```
Checkpoint runs PRAGMA wal\_checkpoint\(\<mode\>\) against the database. Safe to call on a live database. PASSIVE never blocks; TRUNCATE produces the most compact on\-disk layout. On a non\-WAL database the underlying PRAGMA is a no\-op and returns nil.
<a name="DB.Close"></a>
### func \(\*DB\) [Close](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L210>)
```go
func (d *DB) Close() error
```
Close runs PRAGMA wal\_checkpoint\(TRUNCATE\) before closing the underlying connection so the on\-disk file is readable by external SQLite/fossil tooling. The WASM/WASI build path does not use WAL, so the checkpoint is skipped there. Checkpoint errors are joined with the close error so the connection is always closed regardless of checkpoint outcome.
<a name="DB.Driver"></a>
### func \(\*DB\) [Driver](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L242>)
```go
func (d *DB) Driver() string
```
<a name="DB.Exec"></a>
### func \(\*DB\) [Exec](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L246>)
```go
func (d *DB) Exec(query string, args ...any) (sql.Result, error)
```
<a name="DB.Path"></a>
### func \(\*DB\) [Path](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L238>)
```go
func (d *DB) Path() string
```
<a name="DB.Query"></a>
### func \(\*DB\) [Query](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L254>)
```go
func (d *DB) Query(query string, args ...any) (*sql.Rows, error)
```
<a name="DB.QueryRow"></a>
### func \(\*DB\) [QueryRow](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L250>)
```go
func (d *DB) QueryRow(query string, args ...any) *sql.Row
```
<a name="DB.SetApplicationID"></a>
### func \(\*DB\) [SetApplicationID](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L258>)
```go
func (d *DB) SetApplicationID(id int32) error
```
<a name="DB.SqlDB"></a>
### func \(\*DB\) [SqlDB](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L198>)
```go
func (d *DB) SqlDB() *sql.DB
```
SqlDB returns the underlying \*sql.DB connection.
<a name="DB.WithTx"></a>
### func \(\*DB\) [WithTx](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L285>)
```go
func (d *DB) WithTx(fn func(tx *Tx) error) error
```
<a name="DriverConfig"></a>
## type [DriverConfig](<https://github.com/danmestas/go-libfossil/blob/main/db/register.go#L4-L7>)
DriverConfig defines a SQLite driver's name and DSN builder.
```go
type DriverConfig struct {
Name string
BuildDSN func(path string, pragmas map[string]string) string
}
```
<a name="RegisteredDriver"></a>
### func [RegisteredDriver](<https://github.com/danmestas/go-libfossil/blob/main/db/register.go#L31>)
```go
func RegisteredDriver() *DriverConfig
```
RegisteredDriver returns a copy of the currently registered driver config, or nil if none.
<a name="OpenConfig"></a>
## type [OpenConfig](<https://github.com/danmestas/go-libfossil/blob/main/db/config.go#L4-L7>)
OpenConfig allows callers to customize driver selection and pragmas.
```go
type OpenConfig struct {
Driver string // override driver name (empty = use registered driver)
Pragmas map[string]string // additional/override pragmas (merged with defaults)
}
```
<a name="Querier"></a>
## type [Querier](<https://github.com/danmestas/go-libfossil/blob/main/db/querier.go#L8-L12>)
Querier is the common interface satisfied by both \*DB and \*Tx. Functions that need to work inside transactions accept Querier instead of \*DB.
```go
type Querier interface {
Exec(query string, args ...any) (sql.Result, error)
QueryRow(query string, args ...any) *sql.Row
Query(query string, args ...any) (*sql.Rows, error)
}
```
<a name="Tx"></a>
## type [Tx](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L269-L271>)
```go
type Tx struct {
// contains filtered or unexported fields
}
```
<a name="Tx.Exec"></a>
### func \(\*Tx\) [Exec](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L273>)
```go
func (t *Tx) Exec(query string, args ...any) (sql.Result, error)
```
<a name="Tx.Query"></a>
### func \(\*Tx\) [Query](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L281>)
```go
func (t *Tx) Query(query string, args ...any) (*sql.Rows, error)
```
<a name="Tx.QueryRow"></a>
### func \(\*Tx\) [QueryRow](<https://github.com/danmestas/go-libfossil/blob/main/db/db.go#L277>)
```go
func (t *Tx) QueryRow(query string, args ...any) *sql.Row
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
---
# dst
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/dst/api/
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# dst
```go
import "github.com/danmestas/go-libfossil/dst"
```
## Index
- [func AllBlobUUIDsSorted\(r \*repo.Repo\) \(\[\]string, error\)](<#AllBlobUUIDsSorted>)
- [func CheckBlobIntegrity\(nodeID string, r \*repo.Repo\) error](<#CheckBlobIntegrity>)
- [func CheckConvergence\(master \*repo.Repo, leaves map\[NodeID\]\*repo.Repo\) error](<#CheckConvergence>)
- [func CheckDeltaChains\(nodeID string, r \*repo.Repo\) error](<#CheckDeltaChains>)
- [func CheckNoOrphanPhantoms\(nodeID string, r \*repo.Repo\) error](<#CheckNoOrphanPhantoms>)
- [func CheckSubsetOf\(master \*repo.Repo, leaves map\[NodeID\]\*repo.Repo\) error](<#CheckSubsetOf>)
- [func CheckTableSyncConvergence\(repos map\[string\]\*repo.Repo\) error](<#CheckTableSyncConvergence>)
- [func CheckTableSyncIntegrity\(nodeID string, r \*repo.Repo\) error](<#CheckTableSyncIntegrity>)
- [func CheckTagxrefIntegrity\(nodeID string, r \*repo.Repo\) error](<#CheckTagxrefIntegrity>)
- [func CheckUVConvergence\(master \*repo.Repo, leaves map\[NodeID\]\*repo.Repo\) error](<#CheckUVConvergence>)
- [func CheckUVIntegrity\(nodeID string, r \*repo.Repo\) error](<#CheckUVIntegrity>)
- [func CountBlobs\(r \*repo.Repo\) \(int, error\)](<#CountBlobs>)
- [func HasBlob\(r \*repo.Repo, uuid string\) bool](<#HasBlob>)
- [type Action](<#Action>)
- [type ActionType](<#ActionType>)
- [type DefaultNode](<#DefaultNode>)
- [func NewDefaultNode\(r \*repo.Repo, t sync.Transport, projectCode, serverCode string, opts DefaultNodeOpts\) \*DefaultNode](<#NewDefaultNode>)
- [func \(n \*DefaultNode\) Repo\(\) \*repo.Repo](<#DefaultNode.Repo>)
- [func \(n \*DefaultNode\) Tick\(ctx context.Context, event EventType\) Action](<#DefaultNode.Tick>)
- [type DefaultNodeOpts](<#DefaultNodeOpts>)
- [type Event](<#Event>)
- [type EventQueue](<#EventQueue>)
- [func \(q EventQueue\) Len\(\) int](<#EventQueue.Len>)
- [func \(q EventQueue\) Less\(i, j int\) bool](<#EventQueue.Less>)
- [func \(q \*EventQueue\) Pop\(\) any](<#EventQueue.Pop>)
- [func \(q \*EventQueue\) PopEvent\(\) \*Event](<#EventQueue.PopEvent>)
- [func \(q \*EventQueue\) Push\(x any\)](<#EventQueue.Push>)
- [func \(q \*EventQueue\) PushEvent\(e \*Event\)](<#EventQueue.PushEvent>)
- [func \(q EventQueue\) Swap\(i, j int\)](<#EventQueue.Swap>)
- [type EventType](<#EventType>)
- [type InvariantError](<#InvariantError>)
- [func \(e \*InvariantError\) Error\(\) string](<#InvariantError.Error>)
- [type MockFossil](<#MockFossil>)
- [func NewMockFossil\(r \*repo.Repo\) \*MockFossil](<#NewMockFossil>)
- [func \(f \*MockFossil\) Exchange\(ctx context.Context, req \*xfer.Message\) \(\*xfer.Message, error\)](<#MockFossil.Exchange>)
- [func \(f \*MockFossil\) Repo\(\) \*repo.Repo](<#MockFossil.Repo>)
- [func \(f \*MockFossil\) SetBuggify\(b libsync.BuggifyChecker\)](<#MockFossil.SetBuggify>)
- [func \(f \*MockFossil\) StoreArtifact\(data \[\]byte\) \(string, error\)](<#MockFossil.StoreArtifact>)
- [type Node](<#Node>)
- [type NodeID](<#NodeID>)
- [type PeerNetwork](<#PeerNetwork>)
- [func NewPeerNetwork\(rng \*rand.Rand\) \*PeerNetwork](<#NewPeerNetwork>)
- [func \(n \*PeerNetwork\) AddPeer\(id NodeID, r \*repo.Repo\)](<#PeerNetwork.AddPeer>)
- [func \(n \*PeerNetwork\) Heal\(id NodeID\)](<#PeerNetwork.Heal>)
- [func \(n \*PeerNetwork\) HealAll\(\)](<#PeerNetwork.HealAll>)
- [func \(n \*PeerNetwork\) Partition\(id NodeID\)](<#PeerNetwork.Partition>)
- [func \(n \*PeerNetwork\) SetBuggify\(b libsync.BuggifyChecker\)](<#PeerNetwork.SetBuggify>)
- [func \(n \*PeerNetwork\) SetDropRate\(rate float64\)](<#PeerNetwork.SetDropRate>)
- [func \(n \*PeerNetwork\) Transport\(source, target NodeID\) \*PeerTransport](<#PeerNetwork.Transport>)
- [type PeerTransport](<#PeerTransport>)
- [func \(t \*PeerTransport\) Exchange\(ctx context.Context, req \*xfer.Message\) \(\*xfer.Message, error\)](<#PeerTransport.Exchange>)
- [type SeededBuggify](<#SeededBuggify>)
- [func \(b \*SeededBuggify\) Check\(\_ string, probability float64\) bool](<#SeededBuggify.Check>)
- [type SimConfig](<#SimConfig>)
- [type SimNetwork](<#SimNetwork>)
- [func NewSimNetwork\(rng \*rand.Rand, upstream libsync.Transport\) \*SimNetwork](<#NewSimNetwork>)
- [func \(n \*SimNetwork\) Heal\(id NodeID\)](<#SimNetwork.Heal>)
- [func \(n \*SimNetwork\) HealAll\(\)](<#SimNetwork.HealAll>)
- [func \(n \*SimNetwork\) Partition\(id NodeID\)](<#SimNetwork.Partition>)
- [func \(n \*SimNetwork\) SetDropRate\(rate float64\)](<#SimNetwork.SetDropRate>)
- [func \(n \*SimNetwork\) SetTruncateRate\(rate float64\)](<#SimNetwork.SetTruncateRate>)
- [func \(n \*SimNetwork\) Transport\(nodeID NodeID\) \*SimTransport](<#SimNetwork.Transport>)
- [type SimTransport](<#SimTransport>)
- [func \(t \*SimTransport\) Exchange\(ctx context.Context, req \*xfer.Message\) \(\*xfer.Message, error\)](<#SimTransport.Exchange>)
- [type Simulator](<#Simulator>)
- [func New\(cfg SimConfig\) \(\*Simulator, error\)](<#New>)
- [func \(s \*Simulator\) CheckAllConverged\(master \*repo.Repo\) error](<#Simulator.CheckAllConverged>)
- [func \(s \*Simulator\) CheckAllTableSyncConverged\(\) error](<#Simulator.CheckAllTableSyncConverged>)
- [func \(s \*Simulator\) CheckAllUVConverged\(master \*repo.Repo\) error](<#Simulator.CheckAllUVConverged>)
- [func \(s \*Simulator\) CheckSafety\(\) error](<#Simulator.CheckSafety>)
- [func \(s \*Simulator\) CheckTombstoneConvergence\(t \*testing.T, masterRepo \*repo.Repo, tableName string, def repo.TableDef\)](<#Simulator.CheckTombstoneConvergence>)
- [func \(s \*Simulator\) Clock\(\) \*simio.SimClock](<#Simulator.Clock>)
- [func \(s \*Simulator\) Close\(\) error](<#Simulator.Close>)
- [func \(s \*Simulator\) Leaf\(id NodeID\) Node](<#Simulator.Leaf>)
- [func \(s \*Simulator\) LeafIDs\(\) \[\]NodeID](<#Simulator.LeafIDs>)
- [func \(s \*Simulator\) Network\(\) \*SimNetwork](<#Simulator.Network>)
- [func \(s \*Simulator\) Run\(maxSteps int\) error](<#Simulator.Run>)
- [func \(s \*Simulator\) RunUntil\(deadline time.Time\) error](<#Simulator.RunUntil>)
- [func \(s \*Simulator\) ScheduleSyncNow\(id NodeID\)](<#Simulator.ScheduleSyncNow>)
- [func \(s \*Simulator\) ScheduleUVDelete\(id NodeID, at time.Time, name string, mtime int64\)](<#Simulator.ScheduleUVDelete>)
- [func \(s \*Simulator\) ScheduleUVWrite\(id NodeID, at time.Time, name string, data \[\]byte, mtime int64\)](<#Simulator.ScheduleUVWrite>)
- [func \(s \*Simulator\) SetMasterRepo\(r \*repo.Repo\)](<#Simulator.SetMasterRepo>)
- [func \(s \*Simulator\) Step\(\) \(bool, error\)](<#Simulator.Step>)
<a name="AllBlobUUIDsSorted"></a>
## func [AllBlobUUIDsSorted](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L564>)
```go
func AllBlobUUIDsSorted(r *repo.Repo) ([]string, error)
```
AllBlobUUIDsSorted returns a sorted slice of UUIDs for deterministic comparison.
<a name="CheckBlobIntegrity"></a>
## func [CheckBlobIntegrity](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L33>)
```go
func CheckBlobIntegrity(nodeID string, r *repo.Repo) error
```
CheckBlobIntegrity verifies that every blob in the repo has a UUID matching the hash of its expanded content. This catches corruption from buggify \(content.Expand byte\-flip\) or storage bugs.
<a name="CheckConvergence"></a>
## func [CheckConvergence](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L102>)
```go
func CheckConvergence(master *repo.Repo, leaves map[NodeID]*repo.Repo) error
```
CheckConvergence verifies that every leaf repo contains the same set of artifact UUIDs as the master repo.
<a name="CheckDeltaChains"></a>
## func [CheckDeltaChains](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L52>)
```go
func CheckDeltaChains(nodeID string, r *repo.Repo) error
```
CheckDeltaChains verifies that every delta's srcid points to an existing blob \(no dangling references\).
<a name="CheckNoOrphanPhantoms"></a>
## func [CheckNoOrphanPhantoms](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L79>)
```go
func CheckNoOrphanPhantoms(nodeID string, r *repo.Repo) error
```
CheckNoOrphanPhantoms verifies that phantom entries reference blobs that actually exist in the blob table \(they're just missing content\).
<a name="CheckSubsetOf"></a>
## func [CheckSubsetOf](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L142>)
```go
func CheckSubsetOf(master *repo.Repo, leaves map[NodeID]*repo.Repo) error
```
CheckSubsetOf verifies that all artifacts in the master are present in every leaf. Unlike CheckConvergence, this allows leaves to have extra artifacts \(useful when only pull is being tested\).
<a name="CheckTableSyncConvergence"></a>
## func [CheckTableSyncConvergence](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L412>)
```go
func CheckTableSyncConvergence(repos map[string]*repo.Repo) error
```
CheckTableSyncConvergence verifies that all repos have identical rows for every shared synced table. Tables present in some repos but not others are skipped \(schema may still be propagating\).
<a name="CheckTableSyncIntegrity"></a>
## func [CheckTableSyncIntegrity](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L355>)
```go
func CheckTableSyncIntegrity(nodeID string, r *repo.Repo) error
```
CheckTableSyncIntegrity verifies that: 1. Every row in every synced table has a valid PK hash. 2. Every row's mtime is positive. 3. The computed catalog hash is 40 hex chars.
<a name="CheckTagxrefIntegrity"></a>
## func [CheckTagxrefIntegrity](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L296>)
```go
func CheckTagxrefIntegrity(nodeID string, r *repo.Repo) error
```
CheckTagxrefIntegrity verifies that: 1. Every tagxref.rid references a valid blob 2. Every tagxref.tagid references a valid tag 3. Propagated entries \(srcid=0\) have tagtype=2 4. No tagxref.rid references a phantom blob
<a name="CheckUVConvergence"></a>
## func [CheckUVConvergence](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L209>)
```go
func CheckUVConvergence(master *repo.Repo, leaves map[NodeID]*repo.Repo) error
```
CheckUVConvergence verifies that all repos have identical UV content hashes.
<a name="CheckUVIntegrity"></a>
## func [CheckUVIntegrity](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L171>)
```go
func CheckUVIntegrity(nodeID string, r *repo.Repo) error
```
CheckUVIntegrity verifies that every non\-tombstone entry in the unversioned table has a hash matching the SHA1 of its decompressed content, and sz matches the content length.
<a name="CountBlobs"></a>
## func [CountBlobs](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L578>)
```go
func CountBlobs(r *repo.Repo) (int, error)
```
CountBlobs returns the number of non\-phantom blobs in the repo.
<a name="HasBlob"></a>
## func [HasBlob](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L585>)
```go
func HasBlob(r *repo.Repo, uuid string) bool
```
HasBlob checks if a specific artifact exists in the repo.
<a name="Action"></a>
## type [Action](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L19-L23>)
Action is the result of processing a single event via Tick.
```go
type Action struct {
Type ActionType
Result *sync.SyncResult // non-nil when Type == ActionSynced
Err error // non-nil on sync failure
}
```
<a name="ActionType"></a>
## type [ActionType](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L11>)
ActionType classifies the result of processing an event.
```go
type ActionType int
```
<a name="ActionNone"></a>
```go
const (
ActionNone ActionType = iota
ActionSynced // a sync round was executed
)
```
<a name="DefaultNode"></a>
## type [DefaultNode](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L36-L43>)
DefaultNode is a simple Node that calls sync.Sync directly. No NATS, no HTTP — just a repo \+ transport.
```go
type DefaultNode struct {
// contains filtered or unexported fields
}
```
<a name="NewDefaultNode"></a>
### func [NewDefaultNode](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L56>)
```go
func NewDefaultNode(r *repo.Repo, t sync.Transport, projectCode, serverCode string, opts DefaultNodeOpts) *DefaultNode
```
NewDefaultNode creates a Node backed by sync.Sync.
<a name="DefaultNode.Repo"></a>
### func \(\*DefaultNode\) [Repo](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L91>)
```go
func (n *DefaultNode) Repo() *repo.Repo
```
Repo returns the node's Fossil repository.
<a name="DefaultNode.Tick"></a>
### func \(\*DefaultNode\) [Tick](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L73>)
```go
func (n *DefaultNode) Tick(ctx context.Context, event EventType) Action
```
Tick executes a sync cycle for the given event.
<a name="DefaultNodeOpts"></a>
## type [DefaultNodeOpts](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L46-L53>)
DefaultNodeOpts configures a DefaultNode.
```go
type DefaultNodeOpts struct {
Push bool
Pull bool
UV bool
XTableSync bool
Private bool
Buggify sync.BuggifyChecker
}
```
<a name="Event"></a>
## type [Event](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L22-L29>)
Event is a scheduled occurrence in the simulation.
```go
type Event struct {
Time time.Time
Type EventType
NodeID NodeID
UVName string // for EvUVWrite/EvUVDelete: file name
UVData []byte // for EvUVWrite: file content
UVMTime int64 // for EvUVWrite/EvUVDelete: mtime
}
```
<a name="EventQueue"></a>
## type [EventQueue](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L32>)
EventQueue is a min\-heap of events ordered by time.
```go
type EventQueue []*Event
```
<a name="EventQueue.Len"></a>
### func \(EventQueue\) [Len](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L34>)
```go
func (q EventQueue) Len() int
```
<a name="EventQueue.Less"></a>
### func \(EventQueue\) [Less](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L35>)
```go
func (q EventQueue) Less(i, j int) bool
```
<a name="EventQueue.Pop"></a>
### func \(\*EventQueue\) [Pop](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L38>)
```go
func (q *EventQueue) Pop() any
```
<a name="EventQueue.PopEvent"></a>
### func \(\*EventQueue\) [PopEvent](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L53>)
```go
func (q *EventQueue) PopEvent() *Event
```
PopEvent removes and returns the earliest event.
<a name="EventQueue.Push"></a>
### func \(\*EventQueue\) [Push](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L37>)
```go
func (q *EventQueue) Push(x any)
```
<a name="EventQueue.PushEvent"></a>
### func \(\*EventQueue\) [PushEvent](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L48>)
```go
func (q *EventQueue) PushEvent(e *Event)
```
PushEvent adds an event to the queue.
<a name="EventQueue.Swap"></a>
### func \(EventQueue\) [Swap](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L36>)
```go
func (q EventQueue) Swap(i, j int)
```
<a name="EventType"></a>
## type [EventType](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L12>)
EventType classifies simulation events.
```go
type EventType int
```
<a name="EvTimer"></a>
```go
const (
EvTimer EventType = iota // leaf poll timer fired
EvSyncNow // manual sync trigger for a leaf
EvUVWrite // write a UV file to a node's repo
EvUVDelete // delete a UV file from a node's repo
)
```
<a name="InvariantError"></a>
## type [InvariantError](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L18-L22>)
InvariantError records which invariant failed, on which node, and why.
```go
type InvariantError struct {
Invariant string
NodeID string // "master" or leaf ID
Detail string
}
```
<a name="InvariantError.Error"></a>
### func \(\*InvariantError\) [Error](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L24>)
```go
func (e *InvariantError) Error() string
```
<a name="MockFossil"></a>
## type [MockFossil](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L16-L19>)
MockFossil simulates a Fossil master server using the real HandleSync handler. It manages its own repo and implements sync.Transport by dispatching xfer messages to HandleSyncWithOpts.
```go
type MockFossil struct {
// contains filtered or unexported fields
}
```
<a name="NewMockFossil"></a>
### func [NewMockFossil](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L25>)
```go
func NewMockFossil(r *repo.Repo) *MockFossil
```
NewMockFossil creates a MockFossil backed by the given repo.
<a name="MockFossil.Exchange"></a>
### func \(\*MockFossil\) [Exchange](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L45>)
```go
func (f *MockFossil) Exchange(ctx context.Context, req *xfer.Message) (*xfer.Message, error)
```
Exchange handles one xfer request/response round by delegating to the real HandleSyncWithOpts. This ensures the DST tests exercise the same code path as production servers.
<a name="MockFossil.Repo"></a>
### func \(\*MockFossil\) [Repo](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L38>)
```go
func (f *MockFossil) Repo() *repo.Repo
```
Repo returns the mock fossil's repository \(for seeding and invariants\).
<a name="MockFossil.SetBuggify"></a>
### func \(\*MockFossil\) [SetBuggify](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L33>)
```go
func (f *MockFossil) SetBuggify(b libsync.BuggifyChecker)
```
SetBuggify configures fault injection for the handler.
<a name="MockFossil.StoreArtifact"></a>
### func \(\*MockFossil\) [StoreArtifact](<https://github.com/danmestas/go-libfossil/blob/main/dst/mock_fossil.go#L56>)
```go
func (f *MockFossil) StoreArtifact(data []byte) (string, error)
```
StoreArtifact adds a raw artifact to the mock fossil's repo. Returns the UUID. Used by tests to seed the master with content.
<a name="Node"></a>
## type [Node](<https://github.com/danmestas/go-libfossil/blob/main/dst/node.go#L29-L32>)
Node represents a sync participant in the simulation. The simulator drives events by calling Tick; the Node executes a sync cycle and reports the result. EdgeSync can implement this by wrapping its agent.Agent; the DST provides a DefaultNode for in\-module testing.
```go
type Node interface {
Tick(ctx context.Context, event EventType) Action
Repo() *repo.Repo
}
```
<a name="NodeID"></a>
## type [NodeID](<https://github.com/danmestas/go-libfossil/blob/main/dst/event.go#L9>)
NodeID identifies a node in the simulation.
```go
type NodeID string
```
<a name="PeerNetwork"></a>
## type [PeerNetwork](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L16-L22>)
PeerNetwork simulates a peer\-to\-peer network where each leaf's Exchange calls HandleSync on the designated peer's repo. No bridge, no central server — pure leaf\-to\-leaf sync under DST control.
```go
type PeerNetwork struct {
// contains filtered or unexported fields
}
```
<a name="NewPeerNetwork"></a>
### func [NewPeerNetwork](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L25>)
```go
func NewPeerNetwork(rng *rand.Rand) *PeerNetwork
```
NewPeerNetwork creates a simulated peer network.
<a name="PeerNetwork.AddPeer"></a>
### func \(\*PeerNetwork\) [AddPeer](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L37>)
```go
func (n *PeerNetwork) AddPeer(id NodeID, r *repo.Repo)
```
AddPeer registers a leaf's repo as a sync target for other leaves.
<a name="PeerNetwork.Heal"></a>
### func \(\*PeerNetwork\) [Heal](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L60>)
```go
func (n *PeerNetwork) Heal(id NodeID)
```
Heal removes a node from the partition set.
<a name="PeerNetwork.HealAll"></a>
### func \(\*PeerNetwork\) [HealAll](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L65>)
```go
func (n *PeerNetwork) HealAll()
```
HealAll removes all partitions.
<a name="PeerNetwork.Partition"></a>
### func \(\*PeerNetwork\) [Partition](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L55>)
```go
func (n *PeerNetwork) Partition(id NodeID)
```
Partition isolates a node — all messages to/from it are dropped.
<a name="PeerNetwork.SetBuggify"></a>
### func \(\*PeerNetwork\) [SetBuggify](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L50>)
```go
func (n *PeerNetwork) SetBuggify(b libsync.BuggifyChecker)
```
SetBuggify configures fault injection for the handler.
<a name="PeerNetwork.SetDropRate"></a>
### func \(\*PeerNetwork\) [SetDropRate](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L45>)
```go
func (n *PeerNetwork) SetDropRate(rate float64)
```
SetDropRate sets the probability that any message is dropped.
<a name="PeerNetwork.Transport"></a>
### func \(\*PeerNetwork\) [Transport](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L71>)
```go
func (n *PeerNetwork) Transport(source, target NodeID) *PeerTransport
```
Transport returns a sync.Transport for the given source node that routes to a specific target peer's HandleSync.
<a name="PeerTransport"></a>
## type [PeerTransport](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L103-L107>)
PeerTransport implements sync.Transport by routing through the PeerNetwork to a specific target peer.
```go
type PeerTransport struct {
// contains filtered or unexported fields
}
```
<a name="PeerTransport.Exchange"></a>
### func \(\*PeerTransport\) [Exchange](<https://github.com/danmestas/go-libfossil/blob/main/dst/peer_network.go#L110>)
```go
func (t *PeerTransport) Exchange(ctx context.Context, req *xfer.Message) (*xfer.Message, error)
```
Exchange sends a request through the peer network to the target's HandleSync.
<a name="SeededBuggify"></a>
## type [SeededBuggify](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L18-L20>)
SeededBuggify implements sync.BuggifyChecker with a deterministic PRNG.
```go
type SeededBuggify struct {
// contains filtered or unexported fields
}
```
<a name="SeededBuggify.Check"></a>
### func \(\*SeededBuggify\) [Check](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L23>)
```go
func (b *SeededBuggify) Check(_ string, probability float64) bool
```
Check returns true with the given probability, using the seeded PRNG.
<a name="SimConfig"></a>
## type [SimConfig](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L54-L64>)
SimConfig configures a simulation run.
```go
type SimConfig struct {
Seed int64
NumLeaves int
PollInterval time.Duration
TmpDir string // directory for repo files
Upstream libsync.Transport // mock Fossil master
Buggify bool // enable BUGGIFY fault injection
UV bool // sync unversioned files
Private bool // sync private artifacts
SafetyCheckInterval int // run CheckSafety() every N steps; 0 = disabled
}
```
<a name="SimNetwork"></a>
## type [SimNetwork](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L20-L26>)
SimNetwork simulates the network between leaf agents and the upstream transport \(mock Fossil master\). It supports message dropping, response truncation, and network partitions, controlled by a seeded PRNG for deterministic behavior.
In the original EdgeSync DST, messages routed through a Bridge that forwarded to the upstream. Since Bridge.HandleRequest was just upstream.Exchange, SimNetwork now calls the upstream directly.
```go
type SimNetwork struct {
// contains filtered or unexported fields
}
```
<a name="NewSimNetwork"></a>
### func [NewSimNetwork](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L29>)
```go
func NewSimNetwork(rng *rand.Rand, upstream libsync.Transport) *SimNetwork
```
NewSimNetwork creates a simulated network connected to the given upstream transport.
<a name="SimNetwork.Heal"></a>
### func \(\*SimNetwork\) [Heal](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L54>)
```go
func (n *SimNetwork) Heal(id NodeID)
```
Heal removes a node from the partition set.
<a name="SimNetwork.HealAll"></a>
### func \(\*SimNetwork\) [HealAll](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L59>)
```go
func (n *SimNetwork) HealAll()
```
HealAll removes all partitions.
<a name="SimNetwork.Partition"></a>
### func \(\*SimNetwork\) [Partition](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L49>)
```go
func (n *SimNetwork) Partition(id NodeID)
```
Partition isolates a node — all messages to/from it are dropped.
<a name="SimNetwork.SetDropRate"></a>
### func \(\*SimNetwork\) [SetDropRate](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L38>)
```go
func (n *SimNetwork) SetDropRate(rate float64)
```
SetDropRate sets the probability that any message is dropped entirely.
<a name="SimNetwork.SetTruncateRate"></a>
### func \(\*SimNetwork\) [SetTruncateRate](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L44>)
```go
func (n *SimNetwork) SetTruncateRate(rate float64)
```
SetTruncateRate sets the probability that a response is truncated \(random suffix of cards dropped\). Simulates partial delivery.
<a name="SimNetwork.Transport"></a>
### func \(\*SimNetwork\) [Transport](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L65>)
```go
func (n *SimNetwork) Transport(nodeID NodeID) *SimTransport
```
Transport returns a sync.Transport for the given node that routes messages through this simulated network to the upstream.
<a name="SimTransport"></a>
## type [SimTransport](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L90-L93>)
SimTransport implements sync.Transport by routing through the SimNetwork.
```go
type SimTransport struct {
// contains filtered or unexported fields
}
```
<a name="SimTransport.Exchange"></a>
### func \(\*SimTransport\) [Exchange](<https://github.com/danmestas/go-libfossil/blob/main/dst/network.go#L96>)
```go
func (t *SimTransport) Exchange(ctx context.Context, req *xfer.Message) (*xfer.Message, error)
```
Exchange sends a request through the simulated network to the upstream.
<a name="Simulator"></a>
## type [Simulator](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L29-L51>)
Simulator drives a deterministic simulation of multiple leaf nodes syncing through a simulated network to an upstream transport \(mock Fossil master\).
```go
type Simulator struct {
Seed int64
// Stats
Steps int
TotalSyncs int
TotalErrors int
TotalUVSent int
TotalUVRecvd int
TotalUVGimmes int
// contains filtered or unexported fields
}
```
<a name="New"></a>
### func [New](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L69>)
```go
func New(cfg SimConfig) (*Simulator, error)
```
New creates a Simulator with the given configuration. It creates leaf repos, nodes, and the simulated network. All I/O is local SQLite — no NATS or HTTP connections are made.
<a name="Simulator.CheckAllConverged"></a>
### func \(\*Simulator\) [CheckAllConverged](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L260>)
```go
func (s *Simulator) CheckAllConverged(master *repo.Repo) error
```
CheckAllConverged checks convergence between master and all leaves. Only meaningful after a fault\-free sync period.
<a name="Simulator.CheckAllTableSyncConverged"></a>
### func \(\*Simulator\) [CheckAllTableSyncConverged](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L269>)
```go
func (s *Simulator) CheckAllTableSyncConverged() error
```
CheckAllTableSyncConverged checks table sync convergence across all nodes.
<a name="Simulator.CheckAllUVConverged"></a>
### func \(\*Simulator\) [CheckAllUVConverged](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L281>)
```go
func (s *Simulator) CheckAllUVConverged(master *repo.Repo) error
```
CheckAllUVConverged checks UV convergence between master and all leaves.
<a name="Simulator.CheckSafety"></a>
### func \(\*Simulator\) [CheckSafety](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L236>)
```go
func (s *Simulator) CheckSafety() error
```
CheckSafety runs all safety invariants on every node in the simulation.
<a name="Simulator.CheckTombstoneConvergence"></a>
### func \(\*Simulator\) [CheckTombstoneConvergence](<https://github.com/danmestas/go-libfossil/blob/main/dst/invariants.go#L468>)
```go
func (s *Simulator) CheckTombstoneConvergence(t *testing.T, masterRepo *repo.Repo, tableName string, def repo.TableDef)
```
CheckTombstoneConvergence verifies that all nodes agree on which rows are tombstones for each synced table. Two nodes may have different catalog hashes during convergence, but once converged, their tombstone sets must match.
<a name="Simulator.Clock"></a>
### func \(\*Simulator\) [Clock](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L148>)
```go
func (s *Simulator) Clock() *simio.SimClock
```
Clock returns the simulator's virtual clock.
<a name="Simulator.Close"></a>
### func \(\*Simulator\) [Close](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L335>)
```go
func (s *Simulator) Close() error
```
Close cleans up all leaf node repos and disables buggify. Iterates leafIDs \(not map\) for deterministic error reporting.
<a name="Simulator.Leaf"></a>
### func \(\*Simulator\) [Leaf](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L158>)
```go
func (s *Simulator) Leaf(id NodeID) Node
```
Leaf returns the node for the given node ID.
<a name="Simulator.LeafIDs"></a>
### func \(\*Simulator\) [LeafIDs](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L163>)
```go
func (s *Simulator) LeafIDs() []NodeID
```
LeafIDs returns the ordered list of leaf node IDs.
<a name="Simulator.Network"></a>
### func \(\*Simulator\) [Network](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L153>)
```go
func (s *Simulator) Network() *SimNetwork
```
Network returns the simulated network for fault injection.
<a name="Simulator.Run"></a>
### func \(\*Simulator\) [Run](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L303>)
```go
func (s *Simulator) Run(maxSteps int) error
```
Run processes up to maxSteps events. Returns nil on success or the first invariant/error encountered.
<a name="Simulator.RunUntil"></a>
### func \(\*Simulator\) [RunUntil](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L317>)
```go
func (s *Simulator) RunUntil(deadline time.Time) error
```
RunUntil processes events until the clock reaches the given time.
<a name="Simulator.ScheduleSyncNow"></a>
### func \(\*Simulator\) [ScheduleSyncNow](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L173>)
```go
func (s *Simulator) ScheduleSyncNow(id NodeID)
```
ScheduleSyncNow injects a SyncNow event for the given leaf at the current time.
<a name="Simulator.ScheduleUVDelete"></a>
### func \(\*Simulator\) [ScheduleUVDelete](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L194>)
```go
func (s *Simulator) ScheduleUVDelete(id NodeID, at time.Time, name string, mtime int64)
```
ScheduleUVDelete injects a UV delete event for the given node at the specified time.
<a name="Simulator.ScheduleUVWrite"></a>
### func \(\*Simulator\) [ScheduleUVWrite](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L182>)
```go
func (s *Simulator) ScheduleUVWrite(id NodeID, at time.Time, name string, data []byte, mtime int64)
```
ScheduleUVWrite injects a UV write event for the given node at the specified time.
<a name="Simulator.SetMasterRepo"></a>
### func \(\*Simulator\) [SetMasterRepo](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L168>)
```go
func (s *Simulator) SetMasterRepo(r *repo.Repo)
```
SetMasterRepo registers the master repo for UV events targeting "master".
<a name="Simulator.Step"></a>
### func \(\*Simulator\) [Step](<https://github.com/danmestas/go-libfossil/blob/main/dst/simulator.go#L205>)
```go
func (s *Simulator) Step() (bool, error)
```
Step processes the next event in the queue. Returns false if the queue is empty.
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
---
# libfossil
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/libfossil/api/
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# libfossil
```go
import "github.com/danmestas/go-libfossil"
```
## Index
- [Constants](<#constants>)
- [Variables](<#variables>)
- [func Clone\(ctx context.Context, path string, t Transport, opts CloneOpts\) \(\*Repo, \*CloneResult, error\)](<#Clone>)
- [func JulianToTime\(j float64\) time.Time](<#JulianToTime>)
- [func TimeToJulian\(t time.Time\) float64](<#TimeToJulian>)
- [type AnnotateOpts](<#AnnotateOpts>)
- [type AnnotatedLine](<#AnnotatedLine>)
- [type BisectSession](<#BisectSession>)
- [type BuggifyChecker](<#BuggifyChecker>)
- [type Checkout](<#Checkout>)
- [func \(c \*Checkout\) Add\(patterns \[\]string\) \(int, error\)](<#Checkout.Add>)
- [func \(c \*Checkout\) Checkin\(opts CheckoutCommitOpts\) \(rid int64, uuid string, err error\)](<#Checkout.Checkin>)
- [func \(c \*Checkout\) Close\(\) error](<#Checkout.Close>)
- [func \(c \*Checkout\) Conflicts\(\) \(\[\]string, error\)](<#Checkout.Conflicts>)
- [func \(c \*Checkout\) Dir\(\) string](<#Checkout.Dir>)
- [func \(c \*Checkout\) Extract\(rid int64, opts ExtractOpts\) error](<#Checkout.Extract>)
- [func \(c \*Checkout\) HasChanges\(\) \(bool, error\)](<#Checkout.HasChanges>)
- [func \(c \*Checkout\) Merge\(opts CheckoutMergeOpts\) \(CheckoutMergeResult, error\)](<#Checkout.Merge>)
- [func \(c \*Checkout\) Remove\(patterns \[\]string\) error](<#Checkout.Remove>)
- [func \(c \*Checkout\) Rename\(oldName, newName string\) error](<#Checkout.Rename>)
- [func \(c \*Checkout\) ResolveVersion\(name string\) \(int64, error\)](<#Checkout.ResolveVersion>)
- [func \(c \*Checkout\) ResolveWorking\(name string\) \(WorkingVersion, error\)](<#Checkout.ResolveWorking>)
- [func \(c \*Checkout\) Revert\(opts RevertOpts\) error](<#Checkout.Revert>)
- [func \(c \*Checkout\) Status\(\) \(\[\]CheckoutChange, error\)](<#Checkout.Status>)
- [func \(c \*Checkout\) Update\(opts UpdateOpts\) \(UpdateResult, error\)](<#Checkout.Update>)
- [func \(c \*Checkout\) Version\(\) \(int64, string, error\)](<#Checkout.Version>)
- [func \(c \*Checkout\) WouldFork\(\) \(bool, error\)](<#Checkout.WouldFork>)
- [type CheckoutChange](<#CheckoutChange>)
- [type CheckoutCommitOpts](<#CheckoutCommitOpts>)
- [type CheckoutCreateOpts](<#CheckoutCreateOpts>)
- [type CheckoutMergeFile](<#CheckoutMergeFile>)
- [type CheckoutMergeOpts](<#CheckoutMergeOpts>)
- [type CheckoutMergeResult](<#CheckoutMergeResult>)
- [type CheckoutObserver](<#CheckoutObserver>)
- [func NopCheckoutObserver\(\) CheckoutObserver](<#NopCheckoutObserver>)
- [func StdoutCheckoutObserver\(\) CheckoutObserver](<#StdoutCheckoutObserver>)
- [type CheckoutOpenOpts](<#CheckoutOpenOpts>)
- [type CheckpointMode](<#CheckpointMode>)
- [type CloneOpts](<#CloneOpts>)
- [type CloneResult](<#CloneResult>)
- [type CommitEnd](<#CommitEnd>)
- [type CommitOpts](<#CommitOpts>)
- [type CommitStart](<#CommitStart>)
- [type CreateOpts](<#CreateOpts>)
- [type Cursor](<#Cursor>)
- [type DiffEntry](<#DiffEntry>)
- [type EventKind](<#EventKind>)
- [type ExtractEnd](<#ExtractEnd>)
- [type ExtractOpts](<#ExtractOpts>)
- [type ExtractStart](<#ExtractStart>)
- [type FileEntry](<#FileEntry>)
- [type FileToCommit](<#FileToCommit>)
- [type Fork](<#Fork>)
- [type FramedTransport](<#FramedTransport>)
- [type FslError](<#FslError>)
- [func \(e \*FslError\) Error\(\) string](<#FslError.Error>)
- [func \(e \*FslError\) Unwrap\(\) error](<#FslError.Unwrap>)
- [type FslID](<#FslID>)
- [type FslSize](<#FslSize>)
- [type HTTPOption](<#HTTPOption>)
- [func WithHTTPClient\(c \*http.Client\) HTTPOption](<#WithHTTPClient>)
- [type HandleEnd](<#HandleEnd>)
- [type HandleOpts](<#HandleOpts>)
- [type HandleStart](<#HandleStart>)
- [type LogEntry](<#LogEntry>)
- [type LogOpts](<#LogOpts>)
- [type MergeConflict](<#MergeConflict>)
- [type MergeConflictError](<#MergeConflictError>)
- [func \(e \*MergeConflictError\) Error\(\) string](<#MergeConflictError.Error>)
- [func \(e \*MergeConflictError\) Is\(target error\) bool](<#MergeConflictError.Is>)
- [type MergeResult](<#MergeResult>)
- [type MockTransport](<#MockTransport>)
- [func \(t \*MockTransport\) RoundTrip\(\_ context.Context, payload \[\]byte\) \(\[\]byte, error\)](<#MockTransport.RoundTrip>)
- [type PullOpts](<#PullOpts>)
- [type RC](<#RC>)
- [func \(rc RC\) String\(\) string](<#RC.String>)
- [type Repo](<#Repo>)
- [func Create\(path string, opts CreateOpts\) \(\*Repo, error\)](<#Create>)
- [func Open\(path string\) \(\*Repo, error\)](<#Open>)
- [func \(r \*Repo\) Ancestry\(opts LogOpts\) \(\[\]LogEntry, error\)](<#Repo.Ancestry>)
- [func \(r \*Repo\) Annotate\(opts AnnotateOpts\) \(\[\]AnnotatedLine, error\)](<#Repo.Annotate>)
- [func \(r \*Repo\) BranchOpenLeaf\(name string\) \(rid int64, open bool, err error\)](<#Repo.BranchOpenLeaf>)
- [func \(r \*Repo\) BranchTip\(name string\) \(int64, error\)](<#Repo.BranchTip>)
- [func \(r \*Repo\) Checkpoint\(mode CheckpointMode\) error](<#Repo.Checkpoint>)
- [func \(r \*Repo\) Close\(\) error](<#Repo.Close>)
- [func \(r \*Repo\) Commit\(opts CommitOpts\) \(int64, string, error\)](<#Repo.Commit>)
- [func \(r \*Repo\) Config\(key string\) \(string, error\)](<#Repo.Config>)
- [func \(r \*Repo\) CreateCheckout\(dir string, opts CheckoutCreateOpts\) \(\*Checkout, error\)](<#Repo.CreateCheckout>)
- [func \(r \*Repo\) CreateUser\(opts UserOpts\) error](<#Repo.CreateUser>)
- [func \(r \*Repo\) CurrentTrunk\(\) \(int64, error\)](<#Repo.CurrentTrunk>)
- [func \(r \*Repo\) DB\(\) \*db.DB](<#Repo.DB>)
- [func \(r \*Repo\) DeleteUser\(login string\) error](<#Repo.DeleteUser>)
- [func \(r \*Repo\) DetectForks\(\) \(\[\]Fork, error\)](<#Repo.DetectForks>)
- [func \(r \*Repo\) Diff\(ridA, ridB int64, filePath string\) \(\[\]DiffEntry, error\)](<#Repo.Diff>)
- [func \(r \*Repo\) DisableSubmanifests\(\) error](<#Repo.DisableSubmanifests>)
- [func \(r \*Repo\) EnableSubmanifests\(k int\) \(pinned int, warning string, err error\)](<#Repo.EnableSubmanifests>)
- [func \(r \*Repo\) FindCommonAncestor\(ridA, ridB int64\) \(int64, error\)](<#Repo.FindCommonAncestor>)
- [func \(r \*Repo\) GetUser\(login string\) \(User, error\)](<#Repo.GetUser>)
- [func \(r \*Repo\) HandleSync\(ctx context.Context, payload \[\]byte\) \(\[\]byte, error\)](<#Repo.HandleSync>)
- [func \(r \*Repo\) HandleSyncWithOpts\(ctx context.Context, payload \[\]byte, opts HandleOpts\) \(\[\]byte, error\)](<#Repo.HandleSyncWithOpts>)
- [func \(r \*Repo\) Inner\(\) \*repo.Repo](<#Repo.Inner>)
- [func \(r \*Repo\) ListConflictForks\(\) \(\[\]string, error\)](<#Repo.ListConflictForks>)
- [func \(r \*Repo\) ListFiles\(rid int64\) \(\[\]FileEntry, error\)](<#Repo.ListFiles>)
- [func \(r \*Repo\) ListUsers\(\) \(\[\]User, error\)](<#Repo.ListUsers>)
- [func \(r \*Repo\) Merge\(srcBranch, dstBranch, message, user string\) \(int64, string, error\)](<#Repo.Merge>)
- [func \(r \*Repo\) OpenCheckout\(dir string, opts CheckoutOpenOpts\) \(\*Checkout, error\)](<#Repo.OpenCheckout>)
- [func \(r \*Repo\) Path\(\) string](<#Repo.Path>)
- [func \(r \*Repo\) Pull\(ctx context.Context, url string, opts PullOpts\) \(\*SyncResult, error\)](<#Repo.Pull>)
- [func \(r \*Repo\) ReadFile\(rid int64, filePath string\) \(\[\]byte, error\)](<#Repo.ReadFile>)
- [func \(r \*Repo\) ReadFileAt\(version string, filePath string\) \(\[\]byte, error\)](<#Repo.ReadFileAt>)
- [func \(r \*Repo\) Redo\(dir string\) error](<#Repo.Redo>)
- [func \(r \*Repo\) ResolveBranchStart\(name string\) \(int64, error\)](<#Repo.ResolveBranchStart>)
- [func \(r \*Repo\) ResolveConflictFork\(filename string\) error](<#Repo.ResolveConflictFork>)
- [func \(r \*Repo\) ResolveVersion\(name string\) \(int64, error\)](<#Repo.ResolveVersion>)
- [func \(r \*Repo\) RetuneSubmanifests\(k int\) error](<#Repo.RetuneSubmanifests>)
- [func \(r \*Repo\) ServeHTTP\(ctx context.Context, addr string\) error](<#Repo.ServeHTTP>)
- [func \(r \*Repo\) SetCaps\(login, caps string\) error](<#Repo.SetCaps>)
- [func \(r \*Repo\) SetConfig\(key, value string\) error](<#Repo.SetConfig>)
- [func \(r \*Repo\) SetHashPolicy\(name string\) error](<#Repo.SetHashPolicy>)
- [func \(r \*Repo\) SetPassword\(login, password string\) error](<#Repo.SetPassword>)
- [func \(r \*Repo\) StashApply\(dir string, id int64\) error](<#Repo.StashApply>)
- [func \(r \*Repo\) StashClear\(\) error](<#Repo.StashClear>)
- [func \(r \*Repo\) StashDrop\(id int64\) error](<#Repo.StashDrop>)
- [func \(r \*Repo\) StashList\(\) \(\[\]StashEntry, error\)](<#Repo.StashList>)
- [func \(r \*Repo\) StashPop\(dir string\) error](<#Repo.StashPop>)
- [func \(r \*Repo\) StashSave\(dir, comment string\) error](<#Repo.StashSave>)
- [func \(r \*Repo\) Sync\(ctx context.Context, t Transport, opts SyncOpts\) \(\*SyncResult, error\)](<#Repo.Sync>)
- [func \(r \*Repo\) Tag\(opts TagOpts\) \(int64, error\)](<#Repo.Tag>)
- [func \(r \*Repo\) Timeline\(opts TimelineOpts\) \(\[\]TimelineEntry, error\)](<#Repo.Timeline>)
- [func \(r \*Repo\) UUIDFromRID\(rid int64\) \(string, error\)](<#Repo.UUIDFromRID>)
- [func \(r \*Repo\) UVDelete\(name string, mtime time.Time\) error](<#Repo.UVDelete>)
- [func \(r \*Repo\) UVList\(\) \(\[\]UVEntry, error\)](<#Repo.UVList>)
- [func \(r \*Repo\) UVRead\(name string\) \(\[\]byte, int64, string, error\)](<#Repo.UVRead>)
- [func \(r \*Repo\) UVWrite\(name string, content \[\]byte, mtime time.Time\) error](<#Repo.UVWrite>)
- [func \(r \*Repo\) Undo\(dir string\) error](<#Repo.Undo>)
- [func \(r \*Repo\) Verify\(\) error](<#Repo.Verify>)
- [func \(r \*Repo\) WithTx\(fn func\(tx \*db.Tx\) error\) error](<#Repo.WithTx>)
- [func \(r \*Repo\) XferHandler\(\) http.HandlerFunc](<#Repo.XferHandler>)
- [type RevertOpts](<#RevertOpts>)
- [type RoundStats](<#RoundStats>)
- [type ScanEnd](<#ScanEnd>)
- [type SessionEnd](<#SessionEnd>)
- [type SessionStart](<#SessionStart>)
- [type StashEntry](<#StashEntry>)
- [type StatusEntry](<#StatusEntry>)
- [type SyncObserver](<#SyncObserver>)
- [func NopSyncObserver\(\) SyncObserver](<#NopSyncObserver>)
- [func StdoutSyncObserver\(\) SyncObserver](<#StdoutSyncObserver>)
- [type SyncOpts](<#SyncOpts>)
- [type SyncResult](<#SyncResult>)
- [type TableSyncEnd](<#TableSyncEnd>)
- [type TableSyncStart](<#TableSyncStart>)
- [type TagOpts](<#TagOpts>)
- [type TagSpec](<#TagSpec>)
- [type TimelineEntry](<#TimelineEntry>)
- [type TimelineOpts](<#TimelineOpts>)
- [type Transport](<#Transport>)
- [func NewHTTPTransport\(url string, opts ...HTTPOption\) Transport](<#NewHTTPTransport>)
- [type TransportFunc](<#TransportFunc>)
- [func \(f TransportFunc\) RoundTrip\(ctx context.Context, payload \[\]byte\) \(\[\]byte, error\)](<#TransportFunc.RoundTrip>)
- [type UVEntry](<#UVEntry>)
- [type UpdateChange](<#UpdateChange>)
- [type UpdateOpts](<#UpdateOpts>)
- [type UpdateResult](<#UpdateResult>)
- [type User](<#User>)
- [type UserOpts](<#UserOpts>)
- [type WorkingVersion](<#WorkingVersion>)
## Constants
<a name="CheckpointPassive"></a>
```go
const (
CheckpointPassive = db.CheckpointPassive
CheckpointFull = db.CheckpointFull
CheckpointRestart = db.CheckpointRestart
CheckpointTruncate = db.CheckpointTruncate
)
```
<a name="PhantomSize"></a>
```go
const (
PhantomSize FslSize = fsltype.PhantomSize
FossilApplicationID int32 = fsltype.FossilApplicationID
)
```
## Variables
<a name="ErrAmbiguousVersion"></a>ErrAmbiguousVersion is returned by ResolveVersion when a UUID prefix matches more than one artifact \(collision\). Callers can match with errors.Is.
```go
var ErrAmbiguousVersion = errors.New("libfossil: ambiguous version prefix")
```
<a name="ErrArtifactNotFound"></a>ErrArtifactNotFound is returned by UUIDFromRID when the given RID does not correspond to any artifact in the repository's blob table. Callers can match with errors.Is.
```go
var ErrArtifactNotFound = errors.New("libfossil: artifact not found")
```
<a name="ErrFileNotFound"></a>ErrFileNotFound is returned by ReadFile when the requested filePath is not tracked in the given checkin. Callers can match with errors.Is.
```go
var ErrFileNotFound = errors.New("libfossil: file not found in checkin")
```
<a name="ErrMergeConflict"></a>ErrMergeConflict is returned \(wrapped in a MergeConflictError\) when Merge detects any unresolved three\-way conflicts. Callers can check with errors.Is\(err, ErrMergeConflict\) without caring about the file list.
```go
var ErrMergeConflict = errors.New("libfossil: merge has conflicts")
```
<a name="ErrVersionNotFound"></a>ErrVersionNotFound is returned by ResolveVersion when the requested version string does not match any artifact in the repository. Callers can match with errors.Is.
```go
var ErrVersionNotFound = errors.New("libfossil: version not found")
```
<a name="Clone"></a>
## func [Clone](<https://github.com/danmestas/go-libfossil/blob/main/fossil.go#L89>)
```go
func Clone(ctx context.Context, path string, t Transport, opts CloneOpts) (*Repo, *CloneResult, error)
```
Clone performs a full repository clone from a remote Fossil server. It creates a new repository at the given path, runs the clone protocol until convergence, and returns the opened Repo handle and a result summary. On error, the partially\-created repo file is removed. Artifacts the clone rounds leave missing stay phantoms unless opts.PullPhantoms is set.
<a name="JulianToTime"></a>
## func [JulianToTime](<https://github.com/danmestas/go-libfossil/blob/main/julian.go#L15>)
```go
func JulianToTime(j float64) time.Time
```
JulianToTime converts a Fossil Julian day number to time.Time.
<a name="TimeToJulian"></a>
## func [TimeToJulian](<https://github.com/danmestas/go-libfossil/blob/main/julian.go#L10>)
```go
func TimeToJulian(t time.Time) float64
```
TimeToJulian converts a time.Time to a Fossil Julian day number.
<a name="AnnotateOpts"></a>
## type [AnnotateOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L101-L104>)
AnnotateOpts configures an annotate operation.
```go
type AnnotateOpts struct {
FilePath string
StartRID int64
}
```
<a name="AnnotatedLine"></a>
## type [AnnotatedLine](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L93-L98>)
AnnotatedLine is a single line of blame/annotate output.
```go
type AnnotatedLine struct {
Text string
UUID string
User string
Date time.Time
}
```
<a name="BisectSession"></a>
## type [BisectSession](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L107-L109>)
BisectSession holds state for a binary\-search bisect operation.
```go
type BisectSession struct {
// contains filtered or unexported fields
}
```
<a name="BuggifyChecker"></a>
## type [BuggifyChecker](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L36-L38>)
BuggifyChecker controls fault injection for deterministic simulation testing.
```go
type BuggifyChecker interface {
Check(site string, probability float64) bool
}
```
<a name="Checkout"></a>
## type [Checkout](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L16-L18>)
Checkout represents a working directory linked to a Fossil repository. A Checkout is not safe for concurrent use. Callers must serialize access to a single Checkout instance.
```go
type Checkout struct {
// contains filtered or unexported fields
}
```
<a name="Checkout.Add"></a>
### func \(\*Checkout\) [Add](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L253>)
```go
func (c *Checkout) Add(patterns []string) (int, error)
```
Add adds files to version tracking. Returns the number of files added. Files already tracked are silently skipped.
<a name="Checkout.Checkin"></a>
### func \(\*Checkout\) [Checkin](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L308>)
```go
func (c *Checkout) Checkin(opts CheckoutCommitOpts) (rid int64, uuid string, err error)
```
Checkin creates a new checkin from the checkout working directory: every change, or only opts.Files \(a directory names every tracked file under it\). Pending merges become merge parents. Like fossil's commit, it refuses a name it does not track, a commit with nothing changed and no merge pending \(unless opts.AllowEmpty\), files that still hold merge conflict markers \(unless opts.AllowConflict\), and committing only some files of a pending merge. Returns the RID and UUID of the new checkin manifest.
<a name="Checkout.Close"></a>
### func \(\*Checkout\) [Close](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L163>)
```go
func (c *Checkout) Close() error
```
Close closes the checkout database. Does NOT close the repo.
<a name="Checkout.Conflicts"></a>
### func \(\*Checkout\) [Conflicts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L372>)
```go
func (c *Checkout) Conflicts() ([]string, error)
```
Conflicts lists the files, sorted, that hold merge conflict markers: the files a merge or update left in conflict and nobody has resolved yet.
<a name="Checkout.Dir"></a>
### func \(\*Checkout\) [Dir](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L171>)
```go
func (c *Checkout) Dir() string
```
Dir returns the checkout directory path.
<a name="Checkout.Extract"></a>
### func \(\*Checkout\) [Extract](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L188>)
```go
func (c *Checkout) Extract(rid int64, opts ExtractOpts) error
```
Extract writes files from the specified checkin to the working directory and makes it the checkout's current version. Unless opts.Force is set it refuses, changing nothing, when the checkout has unsaved changes or when an untracked file sits where the checkin would write different content.
<a name="Checkout.HasChanges"></a>
### func \(\*Checkout\) [HasChanges](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L220>)
```go
func (c *Checkout) HasChanges() (bool, error)
```
HasChanges reports whether the checkout has any added, removed, renamed or modified files. It reads only the checkout database, so an edit on disk counts once Status \(or an Extract or Commit\) has scanned it; adds, removals and renames always count. Missing files need the disk; Status reports them.
<a name="Checkout.Merge"></a>
### func \(\*Checkout\) [Merge](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L349>)
```go
func (c *Checkout) Merge(opts CheckoutMergeOpts) (CheckoutMergeResult, error)
```
Merge merges another checkin into the checkout, as fossil's merge command does, leaving the result for the next Checkin to commit with the merged\-in checkin as a merge parent. A file both sides changed is merged by its strategy; when the strategy cannot reconcile the changes, fossil's conflict markers are written into the file, and the file is in conflict until they are edited out \(see Conflicts\). A conflicted merge is not an error.
Merge refuses, changing nothing, when the repository lacks content it needs or an added file would overwrite an untracked one. A file edited here but deleted in the merged\-in version is kept and reported. Renames are not followed. Merging the checkout's own version or one of its ancestors does nothing.
<a name="Checkout.Remove"></a>
### func \(\*Checkout\) [Remove](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L265>)
```go
func (c *Checkout) Remove(patterns []string) error
```
Remove removes files from version tracking. Newly added files are deleted from vfile; committed files are marked as deleted.
<a name="Checkout.Rename"></a>
### func \(\*Checkout\) [Rename](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L276>)
```go
func (c *Checkout) Rename(oldName, newName string) error
```
Rename marks a tracked file as renamed and moves it on disk.
<a name="Checkout.ResolveVersion"></a>
### func \(\*Checkout\) [ResolveVersion](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L525>)
```go
func (c *Checkout) ResolveVersion(name string) (int64, error)
```
ResolveVersion resolves name as Repo.ResolveVersion does and also resolves the names relative to this checkout \(repo\-state\-00 Section 8.3\), tried after "tip" and before every other form, as fossil's symbolic\_name\_to\_rid does \(src/name.c\):
```
"current" the checkout's version
"prev", "previous" its primary parent
"next" a child: a primary child first, then the newest link
```
A keyword that names nothing, such as "prev" at a root, falls through to the other forms, as in fossil. The forms that take a name, such as "root:current", resolve it the same way. "ckout" is an ordinary name here: it is a keyword only in the checkout\-inclusive request, ResolveWorking.
<a name="Checkout.ResolveWorking"></a>
### func \(\*Checkout\) [ResolveWorking](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L555>)
```go
func (c *Checkout) ResolveWorking(name string) (WorkingVersion, error)
```
ResolveWorking is fossil's checkout\-inclusive request \("ci\+", symbolic\_name\_to\_rid in src/name.c\): while the checkout has a version, "ckout" names its working files, reported as Working. Every other name, and "ckout" in a checkout with no version, resolves as ResolveVersion does, except that only check\-ins can answer: the request is a check\-in request, so a technote or wiki page carrying the tag does not.
As repo\-state\-00 Section 8.3 says, only "ci\+" has the keyword, so ResolveVersion and Repo.ResolveBranchStart read "ckout" as an ordinary name. It is a keyword only as the whole name: in "root:ckout" or "ckout." the inner name is resolved as a plain check\-in request, as in fossil.
<a name="Checkout.Revert"></a>
### func \(\*Checkout\) [Revert](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L290>)
```go
func (c *Checkout) Revert(opts RevertOpts) error
```
Revert restores files to their checkout version state. If opts.Files is empty, reverts all changed files.
<a name="Checkout.Status"></a>
### func \(\*Checkout\) [Status](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L231>)
```go
func (c *Checkout) Status() ([]CheckoutChange, error)
```
Status scans the working directory and returns the changed files, each classified as added, deleted, missing, renamed or modified, the way fossil's changes command classifies them. Wraps ScanChanges \+ VisitChanges.
<a name="Checkout.Update"></a>
### func \(\*Checkout\) [Update](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L202>)
```go
func (c *Checkout) Update(opts UpdateOpts) (UpdateResult, error)
```
Update updates the checkout to a new version, performing 3\-way merge where needed to preserve local modifications. See UpdateResult for how to distinguish a clean update from one that wrote conflict markers into working\-tree files.
<a name="Checkout.Version"></a>
### func \(\*Checkout\) [Version](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L176>)
```go
func (c *Checkout) Version() (int64, string, error)
```
Version returns the current checkout version \(RID and UUID\).
<a name="Checkout.WouldFork"></a>
### func \(\*Checkout\) [WouldFork](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L409>)
```go
func (c *Checkout) WouldFork() (bool, error)
```
WouldFork reports whether committing on the checkout's version would create a fork: the version already has a child on its own branch \(for example after a pull\), so the commit would become a second leaf. This is fossil's "Would fork" commit refusal; run Update first, or commit to a new branch. Another open leaf elsewhere on the branch does not count.
<a name="CheckoutChange"></a>
## type [CheckoutChange](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L130-L133>)
CheckoutChange describes a single file change in the checkout.
```go
type CheckoutChange struct {
Name string
Change string // "added", "modified", "deleted", "renamed", "missing"
}
```
<a name="CheckoutCommitOpts"></a>
## type [CheckoutCommitOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L82-L97>)
CommitOpts configures creating a checkin from the checkout. \(This type is distinct from the existing libfossil.CommitOpts which takes explicit file content for direct repo commits without a checkout.\)
```go
type CheckoutCommitOpts struct {
Message string
User string
Branch string // empty = current branch
Tags []string // additional tag names
Delta bool
// Files limits the commit to these checkout-relative paths; empty
// commits every change.
Files []string
// AllowConflict commits files that still hold merge conflict markers,
// which Checkin otherwise refuses, as fossil's commit does.
AllowConflict bool
// AllowEmpty commits even when nothing changed, which Checkin otherwise
// refuses, as fossil's commit does.
AllowEmpty bool
}
```
<a name="CheckoutCreateOpts"></a>
## type [CheckoutCreateOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L21-L24>)
CheckoutCreateOpts configures creating a new checkout.
```go
type CheckoutCreateOpts struct {
Env *simio.Env // nil = real env
Observer CheckoutObserver // nil = nop
}
```
<a name="CheckoutMergeFile"></a>
## type [CheckoutMergeFile](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L122-L127>)
CheckoutMergeFile reports what a merge did to one file. Action is one of:
```
"updated" - only the merged-in version changed it; its content was taken
"merged" - both sides changed it and the strategy combined them cleanly
"conflict" - merged with conflict markers written into the file
"kept" - could not be merged; the checkout's copy is unchanged (see Reason)
"forked" - the conflict-fork strategy recorded every version for later
"added" - new in the merged-in version
"deleted" - deleted in the merged-in version, unchanged here
"mode" - only the merged-in version changed its executable bit; taken
```
```go
type CheckoutMergeFile struct {
Name string
Action string
Strategy string // the strategy that merged it, when one ran
Reason string // why the file was kept, for "kept"
}
```
<a name="CheckoutMergeOpts"></a>
## type [CheckoutMergeOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L100-L104>)
CheckoutMergeOpts configures Checkout.Merge.
```go
type CheckoutMergeOpts struct {
Version int64 // rid of the checkin to merge in; required
Strategy string // strategy for every file; "" picks one per file
DryRun bool // report what the merge would do, changing nothing
}
```
<a name="CheckoutMergeResult"></a>
## type [CheckoutMergeResult](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L107-L110>)
CheckoutMergeResult reports a merge.
```go
type CheckoutMergeResult struct {
Ancestor int64 // the common ancestor the merge diffed against
Files []CheckoutMergeFile // sorted by name; empty when there was nothing to merge
}
```
<a name="CheckoutObserver"></a>
## type [CheckoutObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L24-L33>)
CheckoutObserver receives lifecycle callbacks during checkout/commit operations. Use NopCheckoutObserver\(\) for a silent no\-op, or StdoutCheckoutObserver\(\) for stderr logging.
```go
type CheckoutObserver interface {
ExtractStarted(info ExtractStart)
ExtractFileCompleted(name string, change UpdateChange)
ExtractCompleted(info ExtractEnd)
ScanStarted(dir string)
ScanCompleted(info ScanEnd)
CommitStarted(info CommitStart)
CommitCompleted(info CommitEnd)
Error(err error)
}
```
<a name="NopCheckoutObserver"></a>
### func [NopCheckoutObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L146>)
```go
func NopCheckoutObserver() CheckoutObserver
```
NopCheckoutObserver returns a CheckoutObserver that silently discards all events.
<a name="StdoutCheckoutObserver"></a>
### func [StdoutCheckoutObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L224>)
```go
func StdoutCheckoutObserver() CheckoutObserver
```
StdoutCheckoutObserver returns a CheckoutObserver that logs events to stderr.
<a name="CheckoutOpenOpts"></a>
## type [CheckoutOpenOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L27-L31>)
CheckoutOpenOpts configures opening an existing checkout.
```go
type CheckoutOpenOpts struct {
SearchParents bool // search parent dirs for .fslckout
Env *simio.Env // nil = real env
Observer CheckoutObserver
}
```
<a name="CheckpointMode"></a>
## type [CheckpointMode](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L15>)
CheckpointMode mirrors SQLite's PRAGMA wal\_checkpoint\(\<mode\>\) argument.
```go
type CheckpointMode = db.CheckpointMode
```
<a name="CloneOpts"></a>
## type [CloneOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L61-L73>)
CloneOpts configures a clone operation.
```go
type CloneOpts struct {
User string
Password string
Observer SyncObserver
Buggify BuggifyChecker // fault injection for DST (nil = no faults)
// PullPhantoms, when set, makes Clone fetch the artifacts the clone
// rounds left missing with a follow-up pull session, and fail with an
// error if any are still missing after it. That pull departs from
// Section 8.2 of the sync draft, which sends no clone, pull or push card
// after clone_seqno 0, so it is off by default: like fossil(1)'s clone,
// Clone then succeeds with those artifacts left as phantoms.
PullPhantoms bool
}
```
<a name="CloneResult"></a>
## type [CloneResult](<https://github.com/danmestas/go-libfossil/blob/main/fossil.go#L75-L82>)
CloneResult reports what happened during a clone.
```go
type CloneResult struct {
Rounds int
BlobsRecvd int
ArtifactsLinked int
ProjectCode string
ServerCode string
Messages []string
}
```
<a name="CommitEnd"></a>
## type [CommitEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L112-L115>)
CommitEnd describes the completion of a commit operation.
```go
type CommitEnd struct {
UUID string
RID int64
}
```
<a name="CommitOpts"></a>
## type [CommitOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L13-L40>)
CommitOpts configures a commit operation.
```go
type CommitOpts struct {
// Files is the caller-supplied subset of the new commit's tree. When
// ParentID is non-zero, Files is MERGED with the parent's tracked files:
// any name in Files overrides the parent's entry, and any file tracked
// at the parent but not in Files is carried forward into the new manifest.
// This matches `fossil ci`'s full-tree semantics — supplying just the
// changed files does not erase the rest of the tree.
Files []FileToCommit
Comment string
User string
Tags []TagSpec
Time time.Time
ParentID int64
// MergeParents lists additional parents for a merge commit. The resulting
// manifest's P-card is [ParentID, MergeParents...]; ParentID is the primary
// parent (branch tip being committed onto), and each MergeParent contributes
// a secondary plink row (isprim=0).
MergeParents []int64
Delta bool
// PartialManifest, when true, skips the parent-file merge: the resulting
// manifest contains only Files. This is the legacy pre-fix behavior and
// effectively erases every file tracked at the parent that is not in
// Files. Default false matches `fossil ci`. Set true only when the
// caller intentionally wants omission-to-mean-deletion (e.g., tests for
// the diff/deletion path); a dedicated deletion API may replace this
// escape hatch later.
PartialManifest bool
}
```
<a name="CommitStart"></a>
## type [CommitStart](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L105-L109>)
CommitStart describes the beginning of a commit operation.
```go
type CommitStart struct {
Comment string
User string
Files int
}
```
<a name="CreateOpts"></a>
## type [CreateOpts](<https://github.com/danmestas/go-libfossil/blob/main/fossil.go#L14-L26>)
CreateOpts configures repository creation.
```go
type CreateOpts struct {
User string
// ProjectCode optionally sets the repo's project-code. Empty
// generates a fresh one (current behavior). When non-empty, must
// be 40-char lowercase hex (^[0-9a-f]{40}$) — matching the format
// of generated project-codes. Invalid values return an error
// before any file is written.
ProjectCode string
// Rand provides random bytes for project-code and server-code generation.
// Nil defaults to crypto/rand (production). Set to simio.NewSeededRand
// for deterministic simulation testing.
Rand simio.Rand
}
```
<a name="Cursor"></a>
## type [Cursor](<https://github.com/danmestas/go-libfossil/blob/main/types.go#L51>)
Cursor is an opaque pagination token for Timeline. Obtain one from a returned TimelineEntry's Cursor field and pass it back as the next TimelineOpts.After to resume enumeration immediately after that entry. The zero Cursor means "start from the newest event".
Cursor's representation is deliberately hidden: it cannot be constructed from a timestamp and a rid by calling code, only obtained from a TimelineEntry the library already produced. See fsltype.Cursor's doc comment for why — a hand\-built cursor derived from a rounded time.Time is not guaranteed to match the row it claims to follow exactly, which is what silently reintroduces skipped or duplicated rows at a page boundary. LogEntry, Ancestry's result type, has no Cursor field at all: Ancestry's pagination is by Start/Limit, so there is no valid cursor to obtain from it, and the type reflects that instead of documenting it as a hazard.
```go
type Cursor = fsltype.Cursor
```
<a name="DiffEntry"></a>
## type [DiffEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L87-L90>)
DiffEntry describes a unified diff for a single file.
```go
type DiffEntry struct {
Name string
Unified string
}
```
<a name="EventKind"></a>
## type [EventKind](<https://github.com/danmestas/go-libfossil/blob/main/types.go#L19>)
EventKind is the type discriminator on a Timeline entry: one of the single\-letter codes fossil assigns per event.type row. The zero value means "all kinds" — the default Timeline uses when no Type is given.
```go
type EventKind = fsltype.EventKind
```
<a name="EventKindCheckin"></a>
```go
const (
// EventKindCheckin is a check-in ('ci').
EventKindCheckin EventKind = fsltype.EventKindCheckin
// EventKindTechnote is a technote / event artifact ('e').
EventKindTechnote EventKind = fsltype.EventKindTechnote
// EventKindForum is a forum post ('f').
EventKindForum EventKind = fsltype.EventKindForum
// EventKindTag is a tag/control artifact ('g').
EventKindTag EventKind = fsltype.EventKindTag
// EventKindTicket is a ticket change ('t').
EventKindTicket EventKind = fsltype.EventKindTicket
// EventKindWiki is a wiki page edit ('w').
EventKindWiki EventKind = fsltype.EventKindWiki
)
```
<a name="ExtractEnd"></a>
## type [ExtractEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L86-L88>)
ExtractEnd describes the completion of a checkout extraction.
```go
type ExtractEnd struct {
FilesWritten int
}
```
<a name="ExtractOpts"></a>
## type [ExtractOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L34-L36>)
ExtractOpts configures file extraction from a checkin.
```go
type ExtractOpts struct {
Force bool // overwrite uncommitted changes
}
```
<a name="ExtractStart"></a>
## type [ExtractStart](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L80-L83>)
ExtractStart describes the beginning of a checkout extraction.
```go
type ExtractStart struct {
RID int64
Dir string
}
```
<a name="FileEntry"></a>
## type [FileEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L56-L60>)
FileEntry describes a file in a manifest.
```go
type FileEntry struct {
Name string
UUID string
Perm string
}
```
<a name="FileToCommit"></a>
## type [FileToCommit](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L43-L47>)
FileToCommit describes a file to include in a commit.
```go
type FileToCommit struct {
Name string
Content []byte
Perm string
}
```
<a name="Fork"></a>
## type [Fork](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L30-L34>)
Fork describes a divergence point between two branches.
```go
type Fork struct {
Ancestor int64
LocalTip int64
RemoteTip int64
}
```
<a name="FramedTransport"></a>
## type [FramedTransport](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L36-L42>)
FramedTransport is an optional interface a Transport may also implement when it can report the framing signal — such as an HTTP Content\-Type header — that accompanied a reply. Sync uses that signal to select the reply's §4 framing instead of assuming the §4.1 compressed container, which matters when the peer is a different Fossil\-protocol implementation that legitimately replies with the uncompressed plain\-card framing \(e.g. a real Fossil server's clone reply\).
It is optional in the same way http.Flusher is optional on an http.ResponseWriter: a Transport whose framing is fixed by convention \(both ends always emit the compressed container\) need not implement it, and sync falls back to assuming the compressed framing for such a Transport. Callers type\-assert a Transport to FramedTransport and use RoundTripFramed when it is available. Reporting the signal as a return value keeps it per\-call, with no shared mutable state to make a reused Transport unsafe across concurrent calls.
```go
type FramedTransport interface {
Transport
// RoundTripFramed behaves like RoundTrip but also returns the framing
// signal (e.g. the reply's Content-Type) the wire carried for this reply,
// or "" when the transport observed none.
RoundTripFramed(ctx context.Context, payload []byte) (resp []byte, contentType string, err error)
}
```
<a name="FslError"></a>
## type [FslError](<https://github.com/danmestas/go-libfossil/blob/main/errors.go#L61-L65>)
```go
type FslError struct {
Code RC
Msg string
Cause error
}
```
<a name="FslError.Error"></a>
### func \(\*FslError\) [Error](<https://github.com/danmestas/go-libfossil/blob/main/errors.go#L67>)
```go
func (e *FslError) Error() string
```
<a name="FslError.Unwrap"></a>
### func \(\*FslError\) [Unwrap](<https://github.com/danmestas/go-libfossil/blob/main/errors.go#L71>)
```go
func (e *FslError) Unwrap() error
```
<a name="FslID"></a>
## type [FslID](<https://github.com/danmestas/go-libfossil/blob/main/types.go#L6>)
FslID is a row\-id in the blob table \(content\-addressed artifacts\).
```go
type FslID = fsltype.FslID
```
<a name="FslSize"></a>
## type [FslSize](<https://github.com/danmestas/go-libfossil/blob/main/types.go#L9>)
FslSize represents a blob size; negative values indicate phantom blobs.
```go
type FslSize = fsltype.FslSize
```
<a name="HTTPOption"></a>
## type [HTTPOption](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L54>)
HTTPOption configures an HTTP transport.
```go
type HTTPOption func(*httpTransport)
```
<a name="WithHTTPClient"></a>
### func [WithHTTPClient](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L57>)
```go
func WithHTTPClient(c *http.Client) HTTPOption
```
WithHTTPClient sets a custom http.Client for the transport.
<a name="HandleEnd"></a>
## type [HandleEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L64-L66>)
HandleEnd describes the completion of a server\-side sync handle.
```go
type HandleEnd struct {
FilesSent, FilesRecvd int
}
```
<a name="HandleOpts"></a>
## type [HandleOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L47-L58>)
HandleOpts configures server\-side sync handling.
```go
type HandleOpts struct {
Observer SyncObserver
Buggify BuggifyChecker
// LoginCookie is the value of the request's x-f-l-c cookie, which
// carries the login card once the client has seen a server-version
// that reads it (§6.5). This server announces such a release, so fossil
// and go-libfossil clients move their login there after the first
// round: an embedder that serves HandleSyncWithOpts over HTTP must pass
// the cookie through, or those rounds arrive as nobody. XferHandler and
// ServeHTTP read it themselves.
LoginCookie string
}
```
<a name="HandleStart"></a>
## type [HandleStart](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L59-L61>)
HandleStart describes the beginning of a server\-side sync handle.
```go
type HandleStart struct {
RemoteAddr string
}
```
<a name="LogEntry"></a>
## type [LogEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L61-L69>)
LogEntry represents a single event, as returned by Ancestry. Parents is populated for Kind == EventKindCheckin and empty for every other kind — plink, which Parents is derived from, only relates check\-in artifacts, so that is correct, not a gap.
LogEntry carries no pagination cursor: Ancestry paginates by LogOpts.Start/Limit, not by cursor, so there would be nothing valid to put in one. See TimelineEntry, Timeline's result type, for the cursor\-carrying counterpart — this split means an Ancestry entry's \(necessarily invalid\) cursor can no longer be obtained at all, let alone passed to Timeline by mistake.
```go
type LogEntry struct {
RID int64
UUID string
Comment string
User string
Time time.Time
Kind EventKind
Parents []string
}
```
<a name="LogOpts"></a>
## type [LogOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L27-L30>)
LogOpts configures an Ancestry query: a first\-parent walk starting from a specific check\-in.
```go
type LogOpts struct {
Start int64
Limit int
}
```
<a name="MergeConflict"></a>
## type [MergeConflict](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L23-L27>)
MergeConflict describes a conflict region in a file.
```go
type MergeConflict struct {
Name string
StartLine int
EndLine int
}
```
<a name="MergeConflictError"></a>
## type [MergeConflictError](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L43-L45>)
MergeConflictError reports which files had unresolved merge conflicts. Files is sorted alphabetically for deterministic output.
```go
type MergeConflictError struct {
Files []string
}
```
<a name="MergeConflictError.Error"></a>
### func \(\*MergeConflictError\) [Error](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L47>)
```go
func (e *MergeConflictError) Error() string
```
<a name="MergeConflictError.Is"></a>
### func \(\*MergeConflictError\) [Is](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L51>)
```go
func (e *MergeConflictError) Is(target error) bool
```
<a name="MergeResult"></a>
## type [MergeResult](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L17-L20>)
MergeResult describes the outcome of a merge.
```go
type MergeResult struct {
Clean bool
Conflicts []MergeConflict
}
```
<a name="MockTransport"></a>
## type [MockTransport](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L124-L126>)
MockTransport is a test double that delegates to a handler function.
```go
type MockTransport struct {
Handler func(req []byte) []byte
}
```
<a name="MockTransport.RoundTrip"></a>
### func \(\*MockTransport\) [RoundTrip](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L129>)
```go
func (t *MockTransport) RoundTrip(_ context.Context, payload []byte) ([]byte, error)
```
RoundTrip calls the Handler function if set, otherwise returns empty bytes.
<a name="PullOpts"></a>
## type [PullOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_pull.go#L11-L22>)
PullOpts configures a pull\-only sync. Fields are a subset of SyncOpts; Pull is hard\-coded true and Push is hard\-coded false to keep the API surface honest about what Pull does.
```go
type PullOpts struct {
// ProjectCode optionally pins the expected server project code. Empty
// accepts whatever the peer advertises (matches existing Sync semantics).
ProjectCode string
// MaxSend caps the bytes the client will send per round (mostly clones
// of clients with UV files). Zero leaves the existing default in place.
MaxSend int
// Observer receives sync-progress events. nil disables observation.
Observer SyncObserver
}
```
<a name="RC"></a>
## type [RC](<https://github.com/danmestas/go-libfossil/blob/main/errors.go#L8>)
```go
type RC int
```
<a name="RCOK"></a>
```go
const (
RCOK RC = 0
RCError RC = 100
RCNYI RC = 101
RCOOM RC = 102
RCMisuse RC = 103
RCRange RC = 104
RCAccess RC = 105
RCIO RC = 106
RCNotFound RC = 107
RCAlreadyExists RC = 108
RCConsistency RC = 109
RCRepoNeedsRebuild RC = 110
RCNotARepo RC = 111
RCRepoVersion RC = 112
RCDB RC = 113
RCBreak RC = 114
RCStepRow RC = 115
RCStepDone RC = 116
RCStepError RC = 117
RCType RC = 118
RCNotACkout RC = 119
RCRepoMismatch RC = 120
RCChecksumMismatch RC = 121
RCLocked RC = 122
RCConflict RC = 123
RCSizeMismatch RC = 124
RCPhantom RC = 125
RCUnsupported RC = 126
)
```
<a name="RC.String"></a>
### func \(RC\) [String](<https://github.com/danmestas/go-libfossil/blob/main/errors.go#L54>)
```go
func (rc RC) String() string
```
<a name="Repo"></a>
## type [Repo](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L9-L12>)
Repo is an opaque handle to a Fossil repository.
```go
type Repo struct {
// contains filtered or unexported fields
}
```
<a name="Create"></a>
### func [Create](<https://github.com/danmestas/go-libfossil/blob/main/fossil.go#L29>)
```go
func Create(path string, opts CreateOpts) (*Repo, error)
```
Create creates a new Fossil repository at the given path.
<a name="Open"></a>
### func [Open](<https://github.com/danmestas/go-libfossil/blob/main/fossil.go#L66>)
```go
func Open(path string) (*Repo, error)
```
Open opens an existing Fossil repository.
<a name="Repo.Ancestry"></a>
### func \(\*Repo\) [Ancestry](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L128>)
```go
func (r *Repo) Ancestry(opts LogOpts) ([]LogEntry, error)
```
Ancestry walks the primary\-parent chain starting from opts.Start: it emits that check\-in, follows plink where isprim=1 to its parent, and repeats until the chain ends or opts.Limit is reached. This only ever sees first\-parent ancestors of opts.Start — a merge's second parent, a sibling branch head, or any check\-in outside that one chain will never appear. Use Timeline for a repository\-wide view.
<a name="Repo.Annotate"></a>
### func \(\*Repo\) [Annotate](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L112>)
```go
func (r *Repo) Annotate(opts AnnotateOpts) ([]AnnotatedLine, error)
```
Annotate attributes each line of a file to the commit that last changed it.
<a name="Repo.BranchOpenLeaf"></a>
### func \(\*Repo\) [BranchOpenLeaf](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L133>)
```go
func (r *Repo) BranchOpenLeaf(name string) (rid int64, open bool, err error)
```
BranchOpenLeaf names one open leaf of the named branch \(repo\-state\-00 Section 9\): a check\-in whose active branch tag is name, that is a leaf and that is not closed. When the branch has several, the one with the greatest event.mtime is returned, as the draft requires of any report that names a single open leaf. open is false, with a nil error, when the branch has no open leaf: it is not open. An empty name is an error, as in BranchTip; the main branch is named by CurrentTrunk and MainBranch.
Unlike BranchTip, which returns the branch's newest check\-in whether or not it is a leaf or closed, this is fossil's \`branch info\` answer. fossil's query \(branch\_is\_open, src/branch.c\) takes whichever open leaf it meets first; this follows the draft's greatest\-mtime rule.
<a name="Repo.BranchTip"></a>
### func \(\*Repo\) [BranchTip](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L99>)
```go
func (r *Repo) BranchTip(name string) (int64, error)
```
BranchTip returns the RID of the most recent checkin on the named branch. Resolves via the 'branch' propagating tag: the tip is the checkin with the latest event.mtime whose tagxref still has that branch value active. Returns an error if no such branch exists in the repository.
<a name="Repo.Checkpoint"></a>
### func \(\*Repo\) [Checkpoint](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L47>)
```go
func (r *Repo) Checkpoint(mode CheckpointMode) error
```
Checkpoint runs PRAGMA wal\_checkpoint\(\<mode\>\) against the repository. Safe to call on a live repo. CheckpointPassive is non\-blocking and appropriate for periodic background checkpoints. CheckpointTruncate produces a maximally compact on\-disk file readable by external fossil tooling without a subsequent Close.
<a name="Repo.Close"></a>
### func \(\*Repo\) [Close](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L35>)
```go
func (r *Repo) Close() error
```
Close closes the repository and releases resources. As part of close, a WAL TRUNCATE checkpoint is run so the on\-disk repo file is readable by external fossil/SQLite tooling.
<a name="Repo.Commit"></a>
### func \(\*Repo\) [Commit](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L73>)
```go
func (r *Repo) Commit(opts CommitOpts) (int64, string, error)
```
Commit creates a new checkin manifest with the given files and returns the RID \(row ID\) and UUID of the newly created artifact. When ParentID is non\-zero, files tracked at the parent but absent from opts.Files are carried forward into the new manifest \(full\-tree semantics — see the CommitOpts.Files doc\).
<a name="Repo.Config"></a>
### func \(\*Repo\) [Config](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L73>)
```go
func (r *Repo) Config(key string) (string, error)
```
Config reads a configuration value from the repo's config table.
<a name="Repo.CreateCheckout"></a>
### func \(\*Repo\) [CreateCheckout](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L138>)
```go
func (r *Repo) CreateCheckout(dir string, opts CheckoutCreateOpts) (*Checkout, error)
```
CreateCheckout creates a new checkout directory linked to this repository. The directory is created if it does not exist. The checkout is initialized to the tip checkin.
<a name="Repo.CreateUser"></a>
### func \(\*Repo\) [CreateUser](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L23>)
```go
func (r *Repo) CreateUser(opts UserOpts) error
```
CreateUser creates a new user in the repository.
<a name="Repo.CurrentTrunk"></a>
### func \(\*Repo\) [CurrentTrunk](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L296>)
```go
func (r *Repo) CurrentTrunk() (int64, error)
```
CurrentTrunk returns the current trunk \(repo\-state\-00 Section 9\): the check\-in that the main\-branch setting's name resolves to by ResolveVersion's procedure, "trunk" when the setting is unset. Only check\-ins can answer, as in fossil's check\-in request, so a technote tagged with the name does not. The setting is local and not synced, so two repositories holding the same artifacts can name different trunks. fossil resolves it the same way where it needs one: update outside a checkout \(src/update.c, a "ci" request\) and open with no version \(src/db.c\). A name that resolves to nothing returns ErrVersionNotFound \(wrapped\).
<a name="Repo.DB"></a>
### func \(\*Repo\) [DB](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L56>)
```go
func (r *Repo) DB() *db.DB
```
DB returns the underlying database handle for raw SQL queries. Use this when the high\-level Repo methods don't cover your use case.
<a name="Repo.DeleteUser"></a>
### func \(\*Repo\) [DeleteUser](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L54>)
```go
func (r *Repo) DeleteUser(login string) error
```
DeleteUser removes a user from the repository.
<a name="Repo.DetectForks"></a>
### func \(\*Repo\) [DetectForks](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L65>)
```go
func (r *Repo) DetectForks() ([]Fork, error)
```
DetectForks finds divergent branches in the repository.
<a name="Repo.Diff"></a>
### func \(\*Repo\) [Diff](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L151>)
```go
func (r *Repo) Diff(ridA, ridB int64, filePath string) ([]DiffEntry, error)
```
Diff returns the unified diff\(s\) between ridA and ridB.
When filePath is non\-empty, returns 0 or 1 entries for that single file: the file is treated as empty bytes on any side where it is absent, so additions and deletions render as pure insert/delete hunks. An empty slice is returned when both sides are byte\-identical.
When filePath is empty, returns one entry per file that changed between the two checkins \(the union of files across both sides where the content UUID differs or the file exists on only one side\). Entries are sorted by Name for deterministic ordering. An empty slice is returned when the two checkins have identical file sets and content.
Whole\-checkin enumeration is currently name\-keyed: a rename with no content change surfaces as a delete of the old name plus an add of the new name, and permission\-only changes are not reflected. Proper rename and perm\-change detection \(via the underlying mlink table\) is tracked as a follow\-up; per\-file diff behaviour for an explicitly named file is unchanged.
<a name="Repo.DisableSubmanifests"></a>
### func \(\*Repo\) [DisableSubmanifests](<https://github.com/danmestas/go-libfossil/blob/main/repo_submanifest.go#L60>)
```go
func (r *Repo) DisableSubmanifests() error
```
DisableSubmanifests turns tree manifest emission off: later commits are flat, and the pinned k is kept for a later EnableSubmanifests. Existing trees remain \-\- artifact names are immutable, so they cannot be retired \-\- and keep being served, though peers that do not announce sub\-manifest support are still refused them. Unlike the CLI's disable, it returns no note saying so; an embedder that wants to tell its operator must do it itself.
<a name="Repo.EnableSubmanifests"></a>
### func \(\*Repo\) [EnableSubmanifests](<https://github.com/danmestas/go-libfossil/blob/main/repo_submanifest.go#L26>)
```go
func (r *Repo) EnableSubmanifests(k int) (pinned int, warning string, err error)
```
EnableSubmanifests turns on tree manifest emission \(draft\-fossil\-submanifests\-00 §8.1\): from the next commit, check\-ins carry their file sets as sub\-manifest trees. k is the partition parameter, 1 to 12, or 0 to select one. A valid pinned k is kept, and an explicit k that differs from it is refused: changing it is RetuneSubmanifests. A stored k outside 1..12 is no valid pin: an explicit k replaces it, and k = 0 is refused, naming the stored value. With no stored k, an explicit k is pinned, or one is selected as zit selects it: the §6.3 cost over one check\-in's file set, refined by replaying recent history. The check\-in analyzed is the current trunk \(CurrentTrunk, the main\-branch tip, which the next commit most plausibly descends from\); when no check\-in is on the main branch, it is the newest check\-in by time, the highest rid breaking a tie. A request that cannot be met \-\- k outside 1..12, no check\-in at all to select from, or a file set no k partitions \-\- changes neither setting. It returns the pinned k and the warning the operator must be shown: peers that do not announce sub\-manifest support, every fossil among them, are refused trees, and trees cannot be retired.
<a name="Repo.FindCommonAncestor"></a>
### func \(\*Repo\) [FindCommonAncestor](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L56>)
```go
func (r *Repo) FindCommonAncestor(ridA, ridB int64) (int64, error)
```
FindCommonAncestor finds the nearest common ancestor of two checkins.
<a name="Repo.GetUser"></a>
### func \(\*Repo\) [GetUser](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L32>)
```go
func (r *Repo) GetUser(login string) (User, error)
```
GetUser returns information about a user.
<a name="Repo.HandleSync"></a>
### func \(\*Repo\) [HandleSync](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L249>)
```go
func (r *Repo) HandleSync(ctx context.Context, payload []byte) ([]byte, error)
```
HandleSync processes an incoming xfer request \(server\-side\). The payload is a raw xfer\-encoded byte slice; the response is also raw bytes.
<a name="Repo.HandleSyncWithOpts"></a>
### func \(\*Repo\) [HandleSyncWithOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L254>)
```go
func (r *Repo) HandleSyncWithOpts(ctx context.Context, payload []byte, opts HandleOpts) ([]byte, error)
```
HandleSyncWithOpts processes an incoming xfer request with optional configuration.
<a name="Repo.Inner"></a>
### func \(\*Repo\) [Inner](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L30>)
```go
func (r *Repo) Inner() *repo.Repo
```
Inner returns the underlying internal repo handle. This is exported for use by in\-module packages \(e.g., cli/\) that need direct access to the repo DB for raw SQL or internal package calls.
<a name="Repo.ListConflictForks"></a>
### func \(\*Repo\) [ListConflictForks](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L82>)
```go
func (r *Repo) ListConflictForks() ([]string, error)
```
ListConflictForks returns filenames with unresolved conflict\-fork entries.
<a name="Repo.ListFiles"></a>
### func \(\*Repo\) [ListFiles](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L194>)
```go
func (r *Repo) ListFiles(rid int64) ([]FileEntry, error)
```
ListFiles returns the files in a manifest identified by blob row\-id.
<a name="Repo.ListUsers"></a>
### func \(\*Repo\) [ListUsers](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L41>)
```go
func (r *Repo) ListUsers() ([]User, error)
```
ListUsers returns all users in the repository.
<a name="Repo.Merge"></a>
### func \(\*Repo\) [Merge](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L157>)
```go
func (r *Repo) Merge(srcBranch, dstBranch, message, user string) (int64, string, error)
```
Merge performs a three\-way merge of srcBranch into dstBranch and creates a merge commit whose primary parent is dstBranch's tip and whose secondary parent is srcBranch's tip. Returns \(rid, uuid\) of the new commit on success.
Conflict policy: any unresolved conflict in any file aborts the whole operation with a \*MergeConflictError — no commit is written. Callers should check errors.Is\(err, ErrMergeConflict\) to detect this case.
File handling:
- Present on both sides: three\-way merge against the common ancestor.
- Present on only one side \(new file\): kept as\-is.
- In ancestor, missing on one side, unchanged on the other: agreed deletion.
- In ancestor, missing on one side, modified on the other: modify/delete conflict.
<a name="Repo.OpenCheckout"></a>
### func \(\*Repo\) [OpenCheckout](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L150>)
```go
func (r *Repo) OpenCheckout(dir string, opts CheckoutOpenOpts) (*Checkout, error)
```
OpenCheckout opens an existing checkout directory linked to this repository.
<a name="Repo.Path"></a>
### func \(\*Repo\) [Path](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L25>)
```go
func (r *Repo) Path() string
```
Path returns the filesystem path to the repository file.
<a name="Repo.Pull"></a>
### func \(\*Repo\) [Pull](<https://github.com/danmestas/go-libfossil/blob/main/repo_pull.go#L30>)
```go
func (r *Repo) Pull(ctx context.Context, url string, opts PullOpts) (*SyncResult, error)
```
Pull fetches commits and ancillary objects from a Fossil HTTP peer and applies them to this repo. It is a strict pull — nothing is sent.
Tiger Style: hostile inputs panic via assert at the boundary; transport failures return wrapped errors. Idempotent on a repo already at peer's tip \(returns a SyncResult with Rounds=0–1 and FilesRecvd=0\).
<a name="Repo.ReadFile"></a>
### func \(\*Repo\) [ReadFile](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L243>)
```go
func (r *Repo) ReadFile(rid int64, filePath string) ([]byte, error)
```
ReadFile returns the bytes of filePath as they existed in checkin rid. Returns ErrFileNotFound \(wrapped\) if the file is not tracked in that checkin. A file that exists but is empty returns \(\[\]byte\{\}, nil\).
<a name="Repo.ReadFileAt"></a>
### func \(\*Repo\) [ReadFileAt](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L827>)
```go
func (r *Repo) ReadFileAt(version string, filePath string) ([]byte, error)
```
ReadFileAt reads filePath from the checkin identified by a symbolic version name \(e.g. "tip", "trunk", a branch name, a UUID, or a UUID prefix\). It calls ResolveVersion to obtain the RID, then delegates to ReadFile. Use ReadFile directly when you already have a numeric RID.
<a name="Repo.Redo"></a>
### func \(\*Repo\) [Redo](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L132>)
```go
func (r *Repo) Redo(dir string) error
```
Redo re\-applies the last undone operation. Requires a checkout database; not yet wired.
<a name="Repo.ResolveBranchStart"></a>
### func \(\*Repo\) [ResolveBranchStart](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L320>)
```go
func (r *Repo) ResolveBranchStart(name string) (int64, error)
```
ResolveBranchStart resolves name as ResolveVersion does, then returns the first check\-in of the branch the result is on: fossil's branch\-type \("br"\) request \(repo\-state\-00 Section 8.3\), the start of the branch rather than the check\-in its name most recently points at. As Section 8.3 requires, the request is rewritten to a check\-in request first: only check\-ins can match, so a technote tagged with the branch name does not shadow the branch.
Section 8.3 walks back from the result of every form. fossil\(1\) walks only from a "tag:NAME" or plain\-name result \(symbolic\_name\_to\_rid, src/name.c\), so there a hash, "tip" or a date names the check\-in itself; this follows the draft.
<a name="Repo.ResolveConflictFork"></a>
### func \(\*Repo\) [ResolveConflictFork](<https://github.com/danmestas/go-libfossil/blob/main/repo_merge.go#L91>)
```go
func (r *Repo) ResolveConflictFork(filename string) error
```
ResolveConflictFork marks a conflict\-fork entry as resolved.
<a name="Repo.ResolveVersion"></a>
### func \(\*Repo\) [ResolveVersion](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L283>)
```go
func (r *Repo) ResolveVersion(name string) (int64, error)
```
ResolveVersion resolves a symbolic version name to a repository artifact RID.
It follows fossil's symbolic\_name\_to\_rid \(src/name.c\) for the forms go\-libfossil supports, in fossil's order:
1. "tip" — newest check\-in by event.mtime. "" is treated as "tip".
2. "rid:N" — the literal RID N, when that artifact exists.
3. "tag:NAME" — the check\-in carrying sym\-NAME with the greatest event.mtime \(forces a tag lookup even for a hex NAME\).
4. "root:BR" / "start:BR" / "merge\-in:BR" — the origin, first check\-in, or most recent merge\-in of branch BR \(BR itself resolved recursively\).
5. "NAME:TIMESTAMP" — the check\-in carrying sym\-NAME with the greatest event.mtime at or before TIMESTAMP \(UTC\).
6. Artifact hash or 4–64 char hex prefix — unique match against blob.uuid, tried before a plain tag; more than one match is ambiguous.
7. Plain symbolic name — the check\-in carrying sym\-NAME with the greatest event.mtime \(resolves "trunk" and branch names\).
8. Trailing\-punctuation retry — a name pasted from prose that ends in one or two punctuation characters is retried without them.
No match returns ErrVersionNotFound \(wrapped\); a hex prefix matching more than one artifact returns ErrAmbiguousVersion \(wrapped\).
The names relative to an open checkout \("current", "prev", "next"\) are ordinary names here, as in fossil outside a checkout; Checkout's ResolveVersion resolves them.
<a name="Repo.RetuneSubmanifests"></a>
### func \(\*Repo\) [RetuneSubmanifests](<https://github.com/danmestas/go-libfossil/blob/main/repo_submanifest.go#L47>)
```go
func (r *Repo) RetuneSubmanifests(k int) error
```
RetuneSubmanifests pins a new partition parameter k, 1 to 12, for the commits that follow \(draft\-fossil\-submanifests\-00 §6.4\). It is forward only: existing check\-ins are unchanged, and the next tree shares only the sub\-manifests whose bytes are the same under both values.
<a name="Repo.ServeHTTP"></a>
### func \(\*Repo\) [ServeHTTP](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L288>)
```go
func (r *Repo) ServeHTTP(ctx context.Context, addr string) error
```
ServeHTTP starts an HTTP server that accepts Fossil xfer requests. Blocks until ctx is cancelled.
Requests are authorized against the user table: one without a login card gets nobody's capabilities, which in a new repository allow clone and pull but not push. Grant more with SetCaps.
<a name="Repo.SetCaps"></a>
### func \(\*Repo\) [SetCaps](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L68>)
```go
func (r *Repo) SetCaps(login, caps string) error
```
SetCaps updates a user's capability string.
<a name="Repo.SetConfig"></a>
### func \(\*Repo\) [SetConfig](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L82>)
```go
func (r *Repo) SetConfig(key, value string) error
```
SetConfig writes a configuration value to the repo's config table.
<a name="Repo.SetHashPolicy"></a>
### func \(\*Repo\) [SetHashPolicy](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L94>)
```go
func (r *Repo) SetHashPolicy(name string) error
```
SetHashPolicy sets the repository's hash policy by name, as \`fossil hash\-policy NEW\-POLICY\` does. name must be exactly one of sha1, auto, sha3, sha3\-only or shun\-sha1: the match is case\-sensitive, and any other string is an error that leaves the policy unchanged. Asking for auto in a repository that already holds a SHA3\-named artifact sets sha3.
<a name="Repo.SetPassword"></a>
### func \(\*Repo\) [SetPassword](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L59>)
```go
func (r *Repo) SetPassword(login, password string) error
```
SetPassword updates a user's password.
<a name="Repo.StashApply"></a>
### func \(\*Repo\) [StashApply](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L105>)
```go
func (r *Repo) StashApply(dir string, id int64) error
```
StashApply restores a stash entry by ID without removing it.
<a name="Repo.StashClear"></a>
### func \(\*Repo\) [StashClear](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L120>)
```go
func (r *Repo) StashClear() error
```
StashClear removes all stash entries.
<a name="Repo.StashDrop"></a>
### func \(\*Repo\) [StashDrop](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L115>)
```go
func (r *Repo) StashDrop(id int64) error
```
StashDrop removes a stash entry by ID.
<a name="Repo.StashList"></a>
### func \(\*Repo\) [StashList](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L110>)
```go
func (r *Repo) StashList() ([]StashEntry, error)
```
StashList returns all stash entries.
<a name="Repo.StashPop"></a>
### func \(\*Repo\) [StashPop](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L100>)
```go
func (r *Repo) StashPop(dir string) error
```
StashPop restores the most recent stash entry and removes it.
<a name="Repo.StashSave"></a>
### func \(\*Repo\) [StashSave](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L95>)
```go
func (r *Repo) StashSave(dir, comment string) error
```
StashSave saves working\-tree changes to the stash. Requires a checkout database; not yet wired \(Repo only wraps the repo DB\).
<a name="Repo.Sync"></a>
### func \(\*Repo\) [Sync](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L205>)
```go
func (r *Repo) Sync(ctx context.Context, t Transport, opts SyncOpts) (*SyncResult, error)
```
Sync runs a sync session against the given transport.
<a name="Repo.Tag"></a>
### func \(\*Repo\) [Tag](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L53>)
```go
func (r *Repo) Tag(opts TagOpts) (int64, error)
```
Tag creates a control artifact that adds a tag to a target artifact. Returns the UUID of the tag control artifact.
As \`fossil tag add\` does, a name with a reserved prefix \("wiki\-", "tkt\-", "event\-"\) is refused, and when the target is a check\-in the name is placed in the symbolic namespace with a "sym\-" prefix so it resolves as a tag in commands such as update and merge; other artifact types keep the name bare. Pass the raw name: fossil prefixes the raw name, so "x" becomes "sym\-x" and "sym\-x" becomes "sym\-sym\-x" on a check\-in.
<a name="Repo.Timeline"></a>
### func \(\*Repo\) [Timeline](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L166>)
```go
func (r *Repo) Timeline(opts TimelineOpts) ([]TimelineEntry, error)
```
Timeline enumerates the repository's events newest\-first: every row of the event table by default, or just the rows matching opts.Type when set \(canonical \`fossil timeline\`'s \-t/\-\-type default: no filter unless one is given\). Unlike Ancestry, this does not start from or require any particular check\-in — it is a repository\-wide view, not a walk.
Ordering is \(mtime DESC, rid DESC\), a total order with rid as a true tie\-break at exact mtime equality — a deliberate improvement over canonical fossil, which orders by mtime DESC alone with no tie\-break, and paginates with a bare\-timestamp web cursor carrying a one\-second slop, so rows at a page boundary there can repeat or be skipped. Do not "fix" this back to canonical: it is intentional. To page through the full result set, pass the last entry's Cursor back as the next call's TimelineOpts.After — never construct a cursor from a TimelineEntry's Time by hand; see Cursor's doc comment for why that round trip is lossy.
<a name="Repo.UUIDFromRID"></a>
### func \(\*Repo\) [UUIDFromRID](<https://github.com/danmestas/go-libfossil/blob/main/repo_ids.go#L16>)
```go
func (r *Repo) UUIDFromRID(rid int64) (string, error)
```
UUIDFromRID returns the UUID \(manifest hash\) of the artifact identified by rid. The UUID is the stable, content\-addressed identifier for the artifact; the rid is a repository\-local integer that may differ across clones.
Returns ErrArtifactNotFound \(wrapped\) if no artifact with the given rid exists in the repository. The wrapped error message includes the offending rid. Other errors surface as\-is.
<a name="Repo.UVDelete"></a>
### func \(\*Repo\) [UVDelete](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L149>)
```go
func (r *Repo) UVDelete(name string, mtime time.Time) error
```
UVDelete marks an unversioned file as deleted \(tombstone\).
<a name="Repo.UVList"></a>
### func \(\*Repo\) [UVList](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L167>)
```go
func (r *Repo) UVList() ([]UVEntry, error)
```
UVList returns all unversioned file entries.
<a name="Repo.UVRead"></a>
### func \(\*Repo\) [UVRead](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L162>)
```go
func (r *Repo) UVRead(name string) ([]byte, int64, string, error)
```
UVRead reads an unversioned file from the repository. Returns the content, mtime \(unix seconds\), and content hash.
<a name="Repo.UVWrite"></a>
### func \(\*Repo\) [UVWrite](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L137>)
```go
func (r *Repo) UVWrite(name string, content []byte, mtime time.Time) error
```
UVWrite writes an unversioned file to the repository.
<a name="Repo.Undo"></a>
### func \(\*Repo\) [Undo](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L126>)
```go
func (r *Repo) Undo(dir string) error
```
Undo reverts the last commit or merge. Requires a checkout database; not yet wired.
<a name="Repo.Verify"></a>
### func \(\*Repo\) [Verify](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L62>)
```go
func (r *Repo) Verify() error
```
Verify checks repository integrity \(blob checksums, delta chains\).
<a name="Repo.WithTx"></a>
### func \(\*Repo\) [WithTx](<https://github.com/danmestas/go-libfossil/blob/main/repo.go#L59>)
```go
func (r *Repo) WithTx(fn func(tx *db.Tx) error) error
```
WithTx executes fn within a database transaction.
<a name="Repo.XferHandler"></a>
### func \(\*Repo\) [XferHandler](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L277>)
```go
func (r *Repo) XferHandler() http.HandlerFunc
```
XferHandler returns an http.HandlerFunc that decodes Fossil xfer requests, dispatches to HandleSync, and encodes the response. Use this to compose a custom mux alongside operational endpoints \(e.g., /healthz\).
<a name="RevertOpts"></a>
## type [RevertOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L75-L77>)
RevertOpts configures reverting file changes.
```go
type RevertOpts struct {
Files []string // empty = revert all
}
```
<a name="RoundStats"></a>
## type [RoundStats](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L54-L56>)
RoundStats describes the outcome of a single sync round.
```go
type RoundStats struct {
FilesSent, FilesRecvd, BytesSent, BytesRecvd, Gimmes, IGots int
}
```
<a name="ScanEnd"></a>
## type [ScanEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L100-L102>)
ScanEnd describes the completion of a working\-tree scan.
```go
type ScanEnd struct {
FilesScanned int
}
```
<a name="SessionEnd"></a>
## type [SessionEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L49-L51>)
SessionEnd describes the completion of a sync session.
```go
type SessionEnd struct {
Rounds, FilesSent, FilesRecvd int
}
```
<a name="SessionStart"></a>
## type [SessionStart](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L43-L46>)
SessionStart describes the beginning of a sync session.
```go
type SessionStart struct {
ProjectCode string
Push, Pull, UV bool
}
```
<a name="StashEntry"></a>
## type [StashEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L21-L25>)
StashEntry describes a saved stash.
```go
type StashEntry struct {
ID int64
Comment string
Time string
}
```
<a name="StatusEntry"></a>
## type [StatusEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L63-L66>)
StatusEntry describes a changed file in the working tree.
```go
type StatusEntry struct {
Name string
Change string
}
```
<a name="SyncObserver"></a>
## type [SyncObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L10-L20>)
SyncObserver receives lifecycle callbacks during sync operations. Use NopSyncObserver\(\) for a silent no\-op, or StdoutSyncObserver\(\) for stderr logging.
```go
type SyncObserver interface {
Started(info SessionStart)
RoundStarted(round int)
RoundCompleted(round int, stats RoundStats)
Completed(info SessionEnd)
Error(err error)
HandleStarted(info HandleStart)
HandleCompleted(info HandleEnd)
TableSyncStarted(info TableSyncStart)
TableSyncCompleted(info TableSyncEnd)
}
```
<a name="NopSyncObserver"></a>
### func [NopSyncObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L132>)
```go
func NopSyncObserver() SyncObserver
```
NopSyncObserver returns a SyncObserver that silently discards all events.
<a name="StdoutSyncObserver"></a>
### func [StdoutSyncObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L188>)
```go
func StdoutSyncObserver() SyncObserver
```
StdoutSyncObserver returns a SyncObserver that logs events to stderr.
<a name="SyncOpts"></a>
## type [SyncOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L13-L31>)
SyncOpts configures a sync operation.
```go
type SyncOpts struct {
Push bool
Pull bool
UV bool
ProjectCode string
ServerCode string
User string
Password string
PeerID string // identifies this leaf agent instance
MaxSend int
XTableSync bool // enable extension table sync (peer_registry, etc.)
Private bool // enable private artifact sync
// ShareLinks is fossil's --share-links mode (§9.5): a pulling session
// asks the server for the URLs of other copies of the repository and
// keeps each valid one as config link:URL. Off by default.
ShareLinks bool
Observer SyncObserver
Buggify BuggifyChecker
}
```
<a name="SyncResult"></a>
## type [SyncResult](<https://github.com/danmestas/go-libfossil/blob/main/repo_sync.go#L34-L44>)
SyncResult describes the outcome of a sync session.
```go
type SyncResult struct {
Rounds int
FilesSent int
FilesRecvd int
UVFilesSent int
UVFilesRecvd int
UVGimmesSent int
BytesSent int64
BytesRecvd int64
Errors []string
}
```
<a name="TableSyncEnd"></a>
## type [TableSyncEnd](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L74-L77>)
TableSyncEnd describes the completion of a config table sync.
```go
type TableSyncEnd struct {
Table string
RowsSent, RowsRecvd int
}
```
<a name="TableSyncStart"></a>
## type [TableSyncStart](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L69-L71>)
TableSyncStart describes the beginning of a config table sync.
```go
type TableSyncStart struct {
Table string
}
```
<a name="TagOpts"></a>
## type [TagOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L28-L34>)
TagOpts configures a tag operation.
```go
type TagOpts struct {
Name string
TargetID int64
Value string
User string
Time time.Time
}
```
<a name="TagSpec"></a>
## type [TagSpec](<https://github.com/danmestas/go-libfossil/blob/main/repo_checkout.go#L50-L53>)
TagSpec describes a tag to attach to an artifact.
```go
type TagSpec struct {
Name string
Value string
}
```
<a name="TimelineEntry"></a>
## type [TimelineEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L81-L84>)
TimelineEntry represents a single event as returned by Timeline. It extends LogEntry with Cursor, the pagination token for this row: pass it back as the next call's TimelineOpts.After to resume enumeration immediately after this entry. Cursor is always valid \(Cursor.Valid\(\) == true\) on every TimelineEntry Timeline produces.
TimelineEntry values should come from Timeline, not be hand\-assembled. A TimelineEntry built by embedding a LogEntry from Ancestry carries a zero\-value Cursor, which Timeline treats as "start from newest" rather than as an error.
```go
type TimelineEntry struct {
LogEntry
Cursor Cursor
}
```
<a name="TimelineOpts"></a>
## type [TimelineOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_history.go#L34-L48>)
TimelineOpts configures a Timeline query: a repository\-wide enumeration of the event table.
```go
type TimelineOpts struct {
// Type restricts the enumeration to a single event kind. The zero
// value means "all kinds" — the canonical `fossil timeline` default.
Type EventKind
// After, when valid, resumes enumeration immediately following this
// cursor — the next page after whatever TimelineEntry produced it. The
// zero Cursor means "start from the newest event". See Repo.Timeline's
// doc comment for the pagination contract this forms, and Cursor's doc
// comment for why it must come from a TimelineEntry rather than be
// built by hand.
After Cursor
// Limit caps the number of entries returned. Zero or negative means
// unbounded.
Limit int
}
```
<a name="Transport"></a>
## type [Transport](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L16-L18>)
Transport delivers sync payloads between peers. Implementations handle the network layer \(HTTP, NATS, etc.\). Payloads are opaque zlib\-compressed xfer card streams.
```go
type Transport interface {
RoundTrip(ctx context.Context, payload []byte) ([]byte, error)
}
```
<a name="NewHTTPTransport"></a>
### func [NewHTTPTransport](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L45>)
```go
func NewHTTPTransport(url string, opts ...HTTPOption) Transport
```
NewHTTPTransport creates a Transport that speaks Fossil's HTTP /xfer protocol.
<a name="TransportFunc"></a>
## type [TransportFunc](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L138>)
TransportFunc adapts a plain function to the Transport interface. This is the Transport equivalent of http.HandlerFunc.
```go
type TransportFunc func(ctx context.Context, payload []byte) ([]byte, error)
```
<a name="TransportFunc.RoundTrip"></a>
### func \(TransportFunc\) [RoundTrip](<https://github.com/danmestas/go-libfossil/blob/main/transport.go#L141>)
```go
func (f TransportFunc) RoundTrip(ctx context.Context, payload []byte) ([]byte, error)
```
RoundTrip calls the function.
<a name="UVEntry"></a>
## type [UVEntry](<https://github.com/danmestas/go-libfossil/blob/main/repo_extras.go#L37-L42>)
UVEntry describes an unversioned file.
```go
type UVEntry struct {
Name string
Size int64
Mtime time.Time
Hash string
}
```
<a name="UpdateChange"></a>
## type [UpdateChange](<https://github.com/danmestas/go-libfossil/blob/main/observer.go#L91>)
UpdateChange classifies how a file changed.
```go
type UpdateChange string
```
<a name="ChangeAdded"></a>
```go
const (
ChangeAdded UpdateChange = "added"
ChangeModified UpdateChange = "modified"
ChangeDeleted UpdateChange = "deleted"
)
```
<a name="UpdateOpts"></a>
## type [UpdateOpts](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L39-L44>)
UpdateOpts configures updating to a new version with merge.
```go
type UpdateOpts struct {
// TargetRID is the check-in to update to. 0 picks it as fossil's update
// does with no version named: the newest open leaf descended from the
// checkout on its branch. Update fails when several such leaves remain.
TargetRID int64
}
```
<a name="UpdateResult"></a>
## type [UpdateResult](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L68-L72>)
UpdateResult reports what Update actually did. Paths, not counts: a caller needs to know which files to show a user, not merely how many changed. All three slices are sorted \(sort.Strings\) before Update returns, so the order is deterministic — safe for golden\-file tests or reflect.DeepEqual — rather than depending on Go's randomized map iteration order.
Outcome mapping \(Update's error return is the other half of this\):
```
clean - err == nil, Conflicted empty
conflicted - err == nil, Conflicted non-empty
failed - err != nil, UpdateResult is the zero value
```
A non\-empty Conflicted means three\-way merge could not resolve those files cleanly and wrote "\<\<\<\<\<\<\<"\-style conflict markers directly into them on disk. That is NOT an error — Update still returns a nil error, because the update itself succeeded and the working tree is usable; it just isn't clean. A caller that only checks the returned error gets today's pre\-conflict\-detection behavior. A caller that needs to warn a user about marker text in their files must check Conflicted. Every path in Conflicted also appears in FilesWritten: the marker text is what was written there.
```go
type UpdateResult struct {
FilesWritten []string // paths written (added, updated, or merged, clean or not); includes every Conflicted path
FilesRemoved []string // paths deleted from the working tree
Conflicted []string // paths that now contain conflict markers — not an error; also present in FilesWritten
}
```
<a name="User"></a>
## type [User](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L17-L20>)
User describes a Fossil user.
```go
type User struct {
Login string
Caps string
}
```
<a name="UserOpts"></a>
## type [UserOpts](<https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L10-L14>)
UserOpts configures a user creation or update.
```go
type UserOpts struct {
Login string
Password string
Caps string
}
```
<a name="WorkingVersion"></a>
## type [WorkingVersion](<https://github.com/danmestas/go-libfossil/blob/main/checkout.go#L535-L542>)
WorkingVersion is the answer of a checkout\-inclusive request: a check\-in, or the checkout's working files.
```go
type WorkingVersion struct {
// RID is the check-in the name resolves to. When Working is set it is
// the checkout's version, the check-in the working files started from.
RID int64
// Working reports that the name was "ckout": the request asks for the
// files on disk, edits included, rather than for any stored check-in.
Working bool
}
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
---
# observer/otel
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/sdk/observer/otel/api/
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# otel
```go
import "github.com/danmestas/go-libfossil/observer/otel"
```
Package otel provides OpenTelemetry implementations of the libfossil SyncObserver and CheckoutObserver interfaces. Import this package only when you want OTel instrumentation — it pulls in the OTel SDK dependency.
## Index
- [type CheckoutObserver](<#CheckoutObserver>)
- [func NewCheckoutObserver\(\) \*CheckoutObserver](<#NewCheckoutObserver>)
- [func \(o \*CheckoutObserver\) CommitCompleted\(info libfossil.CommitEnd\)](<#CheckoutObserver.CommitCompleted>)
- [func \(o \*CheckoutObserver\) CommitStarted\(info libfossil.CommitStart\)](<#CheckoutObserver.CommitStarted>)
- [func \(o \*CheckoutObserver\) Error\(err error\)](<#CheckoutObserver.Error>)
- [func \(o \*CheckoutObserver\) ExtractCompleted\(info libfossil.ExtractEnd\)](<#CheckoutObserver.ExtractCompleted>)
- [func \(o \*CheckoutObserver\) ExtractFileCompleted\(name string, change libfossil.UpdateChange\)](<#CheckoutObserver.ExtractFileCompleted>)
- [func \(o \*CheckoutObserver\) ExtractStarted\(info libfossil.ExtractStart\)](<#CheckoutObserver.ExtractStarted>)
- [func \(o \*CheckoutObserver\) ScanCompleted\(info libfossil.ScanEnd\)](<#CheckoutObserver.ScanCompleted>)
- [func \(o \*CheckoutObserver\) ScanStarted\(dir string\)](<#CheckoutObserver.ScanStarted>)
- [func \(o \*CheckoutObserver\) String\(\) string](<#CheckoutObserver.String>)
- [type SyncObserver](<#SyncObserver>)
- [func NewSyncObserver\(\) \*SyncObserver](<#NewSyncObserver>)
- [func \(o \*SyncObserver\) Completed\(info libfossil.SessionEnd\)](<#SyncObserver.Completed>)
- [func \(o \*SyncObserver\) Error\(err error\)](<#SyncObserver.Error>)
- [func \(o \*SyncObserver\) HandleCompleted\(info libfossil.HandleEnd\)](<#SyncObserver.HandleCompleted>)
- [func \(o \*SyncObserver\) HandleStarted\(info libfossil.HandleStart\)](<#SyncObserver.HandleStarted>)
- [func \(o \*SyncObserver\) RoundCompleted\(round int, stats libfossil.RoundStats\)](<#SyncObserver.RoundCompleted>)
- [func \(o \*SyncObserver\) RoundStarted\(round int\)](<#SyncObserver.RoundStarted>)
- [func \(o \*SyncObserver\) Started\(info libfossil.SessionStart\)](<#SyncObserver.Started>)
- [func \(o \*SyncObserver\) String\(\) string](<#SyncObserver.String>)
- [func \(o \*SyncObserver\) TableSyncCompleted\(info libfossil.TableSyncEnd\)](<#SyncObserver.TableSyncCompleted>)
- [func \(o \*SyncObserver\) TableSyncStarted\(info libfossil.TableSyncStart\)](<#SyncObserver.TableSyncStarted>)
<a name="CheckoutObserver"></a>
## type [CheckoutObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L208-L223>)
CheckoutObserver implements libfossil.CheckoutObserver using OpenTelemetry spans and metrics.
```go
type CheckoutObserver struct {
// contains filtered or unexported fields
}
```
<a name="NewCheckoutObserver"></a>
### func [NewCheckoutObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L227>)
```go
func NewCheckoutObserver() *CheckoutObserver
```
NewCheckoutObserver returns a CheckoutObserver that records spans and metrics using the OTel global tracer and meter providers.
<a name="CheckoutObserver.CommitCompleted"></a>
### func \(\*CheckoutObserver\) [CommitCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L328>)
```go
func (o *CheckoutObserver) CommitCompleted(info libfossil.CommitEnd)
```
<a name="CheckoutObserver.CommitStarted"></a>
### func \(\*CheckoutObserver\) [CommitStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L314>)
```go
func (o *CheckoutObserver) CommitStarted(info libfossil.CommitStart)
```
<a name="CheckoutObserver.Error"></a>
### func \(\*CheckoutObserver\) [Error](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L347>)
```go
func (o *CheckoutObserver) Error(err error)
```
<a name="CheckoutObserver.ExtractCompleted"></a>
### func \(\*CheckoutObserver\) [ExtractCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L277>)
```go
func (o *CheckoutObserver) ExtractCompleted(info libfossil.ExtractEnd)
```
<a name="CheckoutObserver.ExtractFileCompleted"></a>
### func \(\*CheckoutObserver\) [ExtractFileCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L264>)
```go
func (o *CheckoutObserver) ExtractFileCompleted(name string, change libfossil.UpdateChange)
```
<a name="CheckoutObserver.ExtractStarted"></a>
### func \(\*CheckoutObserver\) [ExtractStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L250>)
```go
func (o *CheckoutObserver) ExtractStarted(info libfossil.ExtractStart)
```
<a name="CheckoutObserver.ScanCompleted"></a>
### func \(\*CheckoutObserver\) [ScanCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L301>)
```go
func (o *CheckoutObserver) ScanCompleted(info libfossil.ScanEnd)
```
<a name="CheckoutObserver.ScanStarted"></a>
### func \(\*CheckoutObserver\) [ScanStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L291>)
```go
func (o *CheckoutObserver) ScanStarted(dir string)
```
<a name="CheckoutObserver.String"></a>
### func \(\*CheckoutObserver\) [String](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L369>)
```go
func (o *CheckoutObserver) String() string
```
<a name="SyncObserver"></a>
## type [SyncObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L23-L39>)
SyncObserver implements libfossil.SyncObserver using OpenTelemetry spans and metrics.
```go
type SyncObserver struct {
// contains filtered or unexported fields
}
```
<a name="NewSyncObserver"></a>
### func [NewSyncObserver](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L43>)
```go
func NewSyncObserver() *SyncObserver
```
NewSyncObserver returns a SyncObserver that records spans and metrics using the OTel global tracer and meter providers.
<a name="SyncObserver.Completed"></a>
### func \(\*SyncObserver\) [Completed](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L126>)
```go
func (o *SyncObserver) Completed(info libfossil.SessionEnd)
```
<a name="SyncObserver.Error"></a>
### func \(\*SyncObserver\) [Error](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L142>)
```go
func (o *SyncObserver) Error(err error)
```
<a name="SyncObserver.HandleCompleted"></a>
### func \(\*SyncObserver\) [HandleCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L166>)
```go
func (o *SyncObserver) HandleCompleted(info libfossil.HandleEnd)
```
<a name="SyncObserver.HandleStarted"></a>
### func \(\*SyncObserver\) [HandleStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L155>)
```go
func (o *SyncObserver) HandleStarted(info libfossil.HandleStart)
```
<a name="SyncObserver.RoundCompleted"></a>
### func \(\*SyncObserver\) [RoundCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L100>)
```go
func (o *SyncObserver) RoundCompleted(round int, stats libfossil.RoundStats)
```
<a name="SyncObserver.RoundStarted"></a>
### func \(\*SyncObserver\) [RoundStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L85>)
```go
func (o *SyncObserver) RoundStarted(round int)
```
<a name="SyncObserver.Started"></a>
### func \(\*SyncObserver\) [Started](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L69>)
```go
func (o *SyncObserver) Started(info libfossil.SessionStart)
```
<a name="SyncObserver.String"></a>
### func \(\*SyncObserver\) [String](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L368>)
```go
func (o *SyncObserver) String() string
```
String returns a human\-readable description.
<a name="SyncObserver.TableSyncCompleted"></a>
### func \(\*SyncObserver\) [TableSyncCompleted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L191>)
```go
func (o *SyncObserver) TableSyncCompleted(info libfossil.TableSyncEnd)
```
<a name="SyncObserver.TableSyncStarted"></a>
### func \(\*SyncObserver\) [TableSyncStarted](<https://github.com/danmestas/go-libfossil/blob/main/observer/otel/otel.go#L180>)
```go
func (o *SyncObserver) TableSyncStarted(info libfossil.TableSyncStart)
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
---
# CLI
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
The `libfossil` command, one page per command group. Every page is the output of the binary's own `--help`.
```text
Usage: libfossil <command> [flags]
Fossil-compatible repository tool (pure Go)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo new [<path>] [flags]
Create a new repository
repo clone [<url> [<path>]] [flags]
Clone a remote repository
repo ci --message=STRING [<files> ...] [flags]
Checkin file changes
repo co [<version>] [flags]
Checkout a version
repo ls [<version>] [flags]
List files in a version
repo timeline [flags]
Show repository history
repo snapshot --message=STRING --path=STRING [flags]
Commit a file's bytes onto trunk, no checkout needed
repo log --path=STRING [flags]
Show the check-ins that changed a path
repo cat <artifact> [flags]
Output artifact content
repo info
Repository statistics
repo hash <files> ... [flags]
Hash files (SHA1 or SHA3)
repo delta create <source> <target> [flags]
Create a delta between two files
repo delta apply <source> <delta> [flags]
Apply a delta to a source file
repo config ls
List all config entries
repo config get <key>
Get a config value
repo config set <key> <value>
Set a config value
repo query <sql>
Execute SQL against repository
repo verify [flags]
Verify repository integrity
repo resolve <name>
Resolve symbolic name to UUID
repo extract [<files> ...] [flags]
Extract files from a version
repo wiki ls
List wiki pages
repo wiki export <page> [flags]
Export a wiki page
repo tag ls [<version>]
List tags on an artifact
repo tag add <tag> [<value>] [flags]
Add a tag to an artifact
repo open [<dir>] [flags]
Open a checkout in a directory
repo status [flags]
Show working directory changes
repo add <files> ... [flags]
Stage files for addition
repo rm <files> ... [flags]
Stage files for removal
repo rename <from> <to> [flags]
Rename a tracked file
repo revert [<files> ...] [flags]
Undo staging changes
repo diff [<version> [<to> [<path>]]] [flags]
Show changes vs a version
repo merge <version> [flags]
Merge a divergent version
repo conflicts ls [flags]
List all conflicts
repo conflicts show <file> [flags]
Show all versions of a conflicted file
repo conflicts pick <file> [flags]
Resolve by picking one version
repo conflicts merge <file> [flags]
Resolve by re-merging with a different strategy
repo conflicts extract <file> [flags]
Extract all versions to disk for manual editing
repo mark-resolved <file> [flags]
Mark a conflict as resolved
repo undo [flags]
Undo last operation
repo redo [flags]
Redo undone operation
repo stash save [flags]
Stash working changes
repo stash pop [flags]
Apply top stash and drop it
repo stash apply [<id>] [flags]
Apply stash without dropping
repo stash ls
List stash entries
repo stash drop <id>
Remove stash entry
repo stash clear
Remove all stash entries
repo bisect good [<version>] [flags]
Mark version as good
repo bisect bad [<version>] [flags]
Mark version as bad
repo bisect next [flags]
Check out midpoint version
repo bisect skip [<version>] [flags]
Skip current version
repo bisect reset [flags]
Clear bisect state
repo bisect ls [flags]
Show bisect path
repo bisect status [flags]
Show bisect state
repo annotate <file> [flags]
Annotate file lines with version history
repo blame <file> [flags]
Alias for annotate
repo branch ls [flags]
List branches
repo branch new <name> [flags]
Create new branch
repo branch close <name> [flags]
Close a branch
repo uv ls
List unversioned files
repo uv put <name> <file>
Add or update an unversioned file
repo uv get <name> [flags]
Retrieve an unversioned file
repo uv delete <name>
Delete an unversioned file (creates tombstone)
repo schema add --columns=STRING <name> [flags]
Register a new synced table
repo schema list
List registered synced tables
repo schema show <name>
Show table schema details
repo schema remove <name>
Remove a synced table registration
repo user add --cap=STRING <login>
Create a new user
repo user list
List all users
repo user update --cap=STRING <login>
Update user capabilities
repo user rm <login>
Delete a user
repo user passwd <login>
Reset user password
repo invite --cap=STRING <login> [flags]
Generate invite token for a user
repo serve [flags]
Serve repository over HTTP for sync/clone
repo submanifests enable [flags]
Write new check-ins as sub-manifest trees
repo submanifests retune --k=INT
Re-pin the partition parameter for later commits
repo submanifests disable
Write new check-ins as flat manifests again
repo submanifests status
Show the sub-manifest settings and whether trees exist
repo cone show [flags]
List the cone's members ("dense" when there is none)
repo cone add <paths> ... [flags]
Widen the cone, or with --not carve paths out of it
repo cone remove <paths> ... [flags]
Remove members of either polarity
repo cone set <paths> ... [flags]
Replace the cone
repo cone dense [flags]
Drop the cone and materialize every file
repo cone test <paths> ... [flags]
Classify paths against the cone and name the deciding member
repo cone store [<paths> ...] [flags]
Show or replace the repository's store cone, fetching what widening covers
repo cone deepen <checkin> [flags]
Move the store's horizon down to reach a check-in, fetching the history it
keeps
repo cone compact
Drop held blobs the store cone elides (irreversible locally)
repo cone cost <checkin>
Report what each horizon rule would hold at a check-in, from this repository
version [flags]
Print version information
Run "libfossil <command> --help" for more information on a command.
```
## Command groups
- [`libfossil repo new`](/docs/reference/cli/repo-new/): Create a new repository
- [`libfossil repo clone`](/docs/reference/cli/repo-clone/): Clone a remote repository
- [`libfossil repo ci`](/docs/reference/cli/repo-ci/): Checkin file changes
- [`libfossil repo co`](/docs/reference/cli/repo-co/): Checkout a version
- [`libfossil repo ls`](/docs/reference/cli/repo-ls/): List files in a version
- [`libfossil repo timeline`](/docs/reference/cli/repo-timeline/): Show repository history
- [`libfossil repo snapshot`](/docs/reference/cli/repo-snapshot/): Commit a file's bytes onto trunk, no checkout needed
- [`libfossil repo log`](/docs/reference/cli/repo-log/): Show the check-ins that changed a path
- [`libfossil repo cat`](/docs/reference/cli/repo-cat/): Output artifact content
- [`libfossil repo info`](/docs/reference/cli/repo-info/): Repository statistics
- [`libfossil repo hash`](/docs/reference/cli/repo-hash/): Hash files (SHA1 or SHA3)
- [`libfossil repo delta`](/docs/reference/cli/repo-delta/): Delta create/apply operations
- [`libfossil repo config`](/docs/reference/cli/repo-config/): Repository configuration
- [`libfossil repo query`](/docs/reference/cli/repo-query/): Execute SQL against repository
- [`libfossil repo verify`](/docs/reference/cli/repo-verify/): Verify repository integrity
- [`libfossil repo resolve`](/docs/reference/cli/repo-resolve/): Resolve symbolic name to UUID
- [`libfossil repo extract`](/docs/reference/cli/repo-extract/): Extract files from a version
- [`libfossil repo wiki`](/docs/reference/cli/repo-wiki/): Wiki page operations
- [`libfossil repo tag`](/docs/reference/cli/repo-tag/): Tag operations
- [`libfossil repo open`](/docs/reference/cli/repo-open/): Open a checkout in a directory
- [`libfossil repo status`](/docs/reference/cli/repo-status/): Show working directory changes
- [`libfossil repo add`](/docs/reference/cli/repo-add/): Stage files for addition
- [`libfossil repo rm`](/docs/reference/cli/repo-rm/): Stage files for removal
- [`libfossil repo rename`](/docs/reference/cli/repo-rename/): Rename a tracked file
- [`libfossil repo revert`](/docs/reference/cli/repo-revert/): Undo staging changes
- [`libfossil repo diff`](/docs/reference/cli/repo-diff/): Show changes vs a version
- [`libfossil repo merge`](/docs/reference/cli/repo-merge/): Merge a divergent version
- [`libfossil repo conflicts`](/docs/reference/cli/repo-conflicts/): List/manage unresolved conflicts
- [`libfossil repo mark-resolved`](/docs/reference/cli/repo-mark-resolved/): Mark a conflict as resolved
- [`libfossil repo undo`](/docs/reference/cli/repo-undo/): Undo last operation
- [`libfossil repo redo`](/docs/reference/cli/repo-redo/): Redo undone operation
- [`libfossil repo stash`](/docs/reference/cli/repo-stash/): Stash working changes
- [`libfossil repo bisect`](/docs/reference/cli/repo-bisect/): Binary search for bugs
- [`libfossil repo annotate`](/docs/reference/cli/repo-annotate/): Annotate file lines with version history
- [`libfossil repo blame`](/docs/reference/cli/repo-blame/): Alias for annotate
- [`libfossil repo branch`](/docs/reference/cli/repo-branch/): Branch operations
- [`libfossil repo uv`](/docs/reference/cli/repo-uv/): Unversioned file operations
- [`libfossil repo schema`](/docs/reference/cli/repo-schema/): Synced table schema operations
- [`libfossil repo user`](/docs/reference/cli/repo-user/): User management
- [`libfossil repo invite`](/docs/reference/cli/repo-invite/): Generate invite token for a user
- [`libfossil repo serve`](/docs/reference/cli/repo-serve/): Serve repository over HTTP for sync/clone
- [`libfossil repo submanifests`](/docs/reference/cli/repo-submanifests/): Sub-manifest tree settings
- [`libfossil repo cone`](/docs/reference/cli/repo-cone/): Show or edit a checkout's sparse cone
- [`libfossil version`](/docs/reference/cli/version/): Print version information
---
# repo new
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-new/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo new [<path>] [flags]
Create a new repository
Arguments:
[<path>] Path for new repository file (default: -R)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--user="" Default user name
```
---
# repo clone
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-clone/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo clone [<url> [<path>]] [flags]
Clone a remote repository
Arguments:
[<url>] Remote Fossil server URL
[<path>] Local path for new repository file
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-u, --user=STRING Username for clone auth
-p, --pass=STRING Password for clone auth
--invite=STRING Invite token (from fossil invite)
--timeout=10m Abort the clone if it runs longer than this;
0 disables the deadline
--horizon=STRING Clone a horizon store: elide blobs below this
check-in, given as tip, a branch or tag,
or its full 40 or 64 digit hash; the origin
resolves a name, or the clone does over what
an origin that cannot sends it; what each rule
would hold needs a local repository ('repo cone
cost') or a peer that exposes it out of band,
as the origin's horizon-served URL may
--depth=INT With --horizon, step the check-in back this
many check-ins along primary parents, stopping
at a root
--leaves With --horizon, also hold every open leaf's
ancestry back to the check-in, for merging
across live branches offline; costly: on a
repository with old unmerged branches that is
nearly the whole history
--structural With --horizon, also elide the manifests below
the check-in, deriving their branch and tag
state from the origin's seed
--cone=CONE,... Clone a sparse store: fetch only this path's
subtree (repeatable)
--cone-not=CONE-NOT,... Carve this path out of a --cone (repeatable)
--seed-key=STRING The origin's public key, an SSH public key line
or an OpenPGP fingerprint: with --structural, a
horizon seed not signed by it is discarded and
the clone falls back to the content horizon;
kept as the horizon-seed-key setting
```
---
# repo ci
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-ci/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo ci --message=STRING [<files> ...] [flags]
Checkin file changes
Arguments:
[<files> ...] Files to commit (default: all changes)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--no-sync Suppress optional autosync, not required-content
recovery
-m, --message=STRING Checkin comment
--user=STRING Checkin user (default: OS username)
--branch=STRING Branch name for this checkin
--allow-conflict Commit files that still hold merge conflict markers
--allow-empty Commit even when nothing has changed
--nosign Do not sign this check-in, even with the clearsign
setting on
-d, --dir="." Checkout directory
```
---
# repo co
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-co/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo co [<version>] [flags]
Checkout a version
Arguments:
[<version>] Version to checkout (default: tip)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Output directory (default: current dir)
--force Overwrite existing files
```
---
# repo ls
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-ls/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo ls [<version>] [flags]
List files in a version
Arguments:
[<version>] Version to list (default: tip)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-l, --long Show sizes and hashes
```
---
# repo timeline
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-timeline/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo timeline [flags]
Show repository history
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-n, --limit=20 Number of entries
```
---
# repo snapshot
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-snapshot/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo snapshot --message=STRING --path=STRING [flags]
Commit a file's bytes onto trunk, no checkout needed
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-m, --message=STRING Checkin comment
--path=STRING File name in the repository (relative,
slash-separated); the bytes come from this path on
disk unless --stdin
--stdin Read the bytes from stdin instead of from --path on
disk
--user=STRING Checkin user (default: OS username)
--json Print {"uuid":...,"changed":...} instead of the bare
uuid
```
---
# repo log
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-log/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo log --path=STRING [flags]
Show the check-ins that changed a path
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--path=STRING File name in the repository
--json Print a JSON array instead of text
-n, --limit=INT Number of entries (default: all)
```
---
# repo cat
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-cat/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo cat <artifact> [flags]
Output artifact content
Arguments:
<artifact> Artifact UUID or prefix; with --at, the file name
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-r, --at=STRING Version to read the file from (tip, trunk, a branch,
a uuid or prefix)
--raw Output raw blob (no delta expansion)
```
---
# repo info
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-info/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo info
Repository statistics
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo hash
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-hash/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo hash <files> ... [flags]
Hash files (SHA1 or SHA3)
Arguments:
<files> ... Files to hash
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--sha3 Use SHA3-256 instead of SHA1
```
---
# repo delta
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-delta/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo delta <command>
Delta create/apply operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo delta create <source> <target> [flags]
Create a delta between two files
repo delta apply <source> <delta> [flags]
Apply a delta to a source file
```
## repo delta create
```text
Usage: libfossil repo delta create <source> <target> [flags]
Create a delta between two files
Arguments:
<source> Source (original) file
<target> Target (new) file
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-o, --output=STRING Output file (default: stdout)
```
## repo delta apply
```text
Usage: libfossil repo delta apply <source> <delta> [flags]
Apply a delta to a source file
Arguments:
<source> Source (original) file
<delta> Delta file
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-o, --output=STRING Output file (default: stdout)
```
---
# repo config
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-config/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo config <command>
Repository configuration
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo config ls
List all config entries
repo config get <key>
Get a config value
repo config set <key> <value>
Set a config value
```
## repo config ls
```text
Usage: libfossil repo config ls
List all config entries
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo config get
```text
Usage: libfossil repo config get <key>
Get a config value
Arguments:
<key> Config key to get
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo config set
```text
Usage: libfossil repo config set <key> <value>
Set a config value
Arguments:
<key> Config key
<value> Config value
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo query
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-query/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo query <sql>
Execute SQL against repository
Arguments:
<sql> SQL query to execute
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo verify
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-verify/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo verify [flags]
Verify repository integrity
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--seed Verify the structural horizon's seed by fetching the
history below it (keeps the content horizon)
```
---
# repo resolve
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-resolve/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo resolve <name>
Resolve symbolic name to UUID
Arguments:
<name> Symbolic name, UUID, or prefix to resolve (e.g. trunk, tip, UUID
prefix)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo extract
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-extract/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo extract [<files> ...] [flags]
Extract files from a version
Arguments:
[<files> ...] Files to extract (default: all)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--version=STRING Version to extract from (default: tip)
-d, --dir="." Output directory
```
---
# repo wiki
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-wiki/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo wiki <command>
Wiki page operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo wiki ls
List wiki pages
repo wiki export <page> [flags]
Export a wiki page
```
## repo wiki ls
```text
Usage: libfossil repo wiki ls
List wiki pages
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo wiki export
```text
Usage: libfossil repo wiki export <page> [flags]
Export a wiki page
Arguments:
<page> Wiki page name or artifact UUID
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-o, --output=STRING Output file (default: stdout)
```
---
# repo tag
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-tag/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo tag <command>
Tag operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo tag ls [<version>]
List tags on an artifact
repo tag add <tag> [<value>] [flags]
Add a tag to an artifact
```
## repo tag ls
```text
Usage: libfossil repo tag ls [<version>]
List tags on an artifact
Arguments:
[<version>] Version to list tags for (default: tip)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo tag add
```text
Usage: libfossil repo tag add <tag> [<value>] [flags]
Add a tag to an artifact
Arguments:
<tag> Tag name
[<value>] Tag value (optional)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--version=STRING Version to tag (default: tip)
```
---
# repo open
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-open/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo open [<dir>] [flags]
Open a checkout in a directory
Arguments:
[<dir>] Checkout directory (default: current dir)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--cone=CONE,... Make a sparse checkout: materialize and track
only this path's subtree (repeatable)
--cone-not=CONE-NOT,... Exclude this path's subtree from an enclosing
--cone (repeatable)
```
---
# repo status
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-status/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo status [flags]
Show working directory changes
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory to scan
```
---
# repo add
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-add/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo add <files> ... [flags]
Stage files for addition
Arguments:
<files> ... Files to stage for addition
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo rm
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-rm/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo rm <files> ... [flags]
Stage files for removal
Arguments:
<files> ... Files to stage for removal
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo rename
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-rename/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo rename <from> <to> [flags]
Rename a tracked file
Arguments:
<from> Current file name
<to> New file name
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo revert
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-revert/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo revert [<files> ...] [flags]
Undo staging changes
Arguments:
[<files> ...] Files to revert (default: all)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo diff
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-diff/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo diff [<version> [<to> [<path>]]] [flags]
Show changes vs a version
Arguments:
[<version>] Version to diff against (default: tip)
[<to>] Second version: diff Version against it instead of the working
directory
[<path>] With two versions, only this file (default: every changed file)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--json With two versions, print a JSON array of {name, unified}
instead of text
-d, --dir="." Working directory to compare
-U, --unified=3 Lines of context
```
---
# repo merge
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-merge/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo merge <version> [flags]
Merge a divergent version
Arguments:
<version> Version to merge into current checkout
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--strategy=STRING Override merge strategy for all files
--dry-run Show what would be merged without writing
-d, --dir="." Checkout directory
```
---
# repo conflicts
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-conflicts/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo conflicts <command> [flags]
List/manage unresolved conflicts
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
Commands:
repo conflicts ls [flags]
List all conflicts
repo conflicts show <file> [flags]
Show all versions of a conflicted file
repo conflicts pick <file> [flags]
Resolve by picking one version
repo conflicts merge <file> [flags]
Resolve by re-merging with a different strategy
repo conflicts extract <file> [flags]
Extract all versions to disk for manual editing
```
## repo conflicts ls
```text
Usage: libfossil repo conflicts ls [flags]
List all conflicts
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo conflicts show
```text
Usage: libfossil repo conflicts show <file> [flags]
Show all versions of a conflicted file
Arguments:
<file> Conflicted file to show
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo conflicts pick
```text
Usage: libfossil repo conflicts pick <file> [flags]
Resolve by picking one version
Arguments:
<file> Conflicted file to resolve
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
--local Keep local version
--remote Keep remote version
--base Revert to base version
-d, --dir="." Checkout directory
```
## repo conflicts merge
```text
Usage: libfossil repo conflicts merge <file> [flags]
Resolve by re-merging with a different strategy
Arguments:
<file> Conflicted file to re-merge
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
--strategy="three-way" Strategy to use
-d, --dir="." Checkout directory
```
## repo conflicts extract
```text
Usage: libfossil repo conflicts extract <file> [flags]
Extract all versions to disk for manual editing
Arguments:
<file> Conflicted file to extract
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
-d, --dir="." Output directory
```
---
# repo mark-resolved
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-mark-resolved/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo mark-resolved <file> [flags]
Mark a conflict as resolved
Arguments:
<file> File to mark as resolved
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo undo
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-undo/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo undo [flags]
Undo last operation
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo redo
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-redo/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo redo [flags]
Redo undone operation
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo stash
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-stash/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo stash <command>
Stash working changes
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo stash save [flags]
Stash working changes
repo stash pop [flags]
Apply top stash and drop it
repo stash apply [<id>] [flags]
Apply stash without dropping
repo stash ls
List stash entries
repo stash drop <id>
Remove stash entry
repo stash clear
Remove all stash entries
```
## repo stash save
```text
Usage: libfossil repo stash save [flags]
Stash working changes
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-m, --message="" Stash message
-d, --dir="." Checkout directory
```
## repo stash pop
```text
Usage: libfossil repo stash pop [flags]
Apply top stash and drop it
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo stash apply
```text
Usage: libfossil repo stash apply [<id>] [flags]
Apply stash without dropping
Arguments:
[<id>] Stash ID to apply (default: latest)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo stash ls
```text
Usage: libfossil repo stash ls
List stash entries
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo stash drop
```text
Usage: libfossil repo stash drop <id>
Remove stash entry
Arguments:
<id> Stash ID to drop
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo stash clear
```text
Usage: libfossil repo stash clear
Remove all stash entries
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo bisect
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-bisect/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo bisect <command>
Binary search for bugs
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo bisect good [<version>] [flags]
Mark version as good
repo bisect bad [<version>] [flags]
Mark version as bad
repo bisect next [flags]
Check out midpoint version
repo bisect skip [<version>] [flags]
Skip current version
repo bisect reset [flags]
Clear bisect state
repo bisect ls [flags]
Show bisect path
repo bisect status [flags]
Show bisect state
```
## repo bisect good
```text
Usage: libfossil repo bisect good [<version>] [flags]
Mark version as good
Arguments:
[<version>] Version to mark (default: current checkout)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect bad
```text
Usage: libfossil repo bisect bad [<version>] [flags]
Mark version as bad
Arguments:
[<version>] Version to mark (default: current checkout)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect next
```text
Usage: libfossil repo bisect next [flags]
Check out midpoint version
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect skip
```text
Usage: libfossil repo bisect skip [<version>] [flags]
Skip current version
Arguments:
[<version>] Version to skip (default: current checkout)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect reset
```text
Usage: libfossil repo bisect reset [flags]
Clear bisect state
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect ls
```text
Usage: libfossil repo bisect ls [flags]
Show bisect path
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo bisect status
```text
Usage: libfossil repo bisect status [flags]
Show bisect state
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
---
# repo annotate
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-annotate/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo annotate <file> [flags]
Annotate file lines with version history
Arguments:
<file> File to annotate
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--version=STRING Starting version (default: tip)
```
---
# repo blame
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-blame/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo blame <file> [flags]
Alias for annotate
Arguments:
<file> File to annotate
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--version=STRING Starting version (default: tip)
```
---
# repo branch
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-branch/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo branch <command>
Branch operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo branch ls [flags]
List branches
repo branch new <name> [flags]
Create new branch
repo branch close <name> [flags]
Close a branch
```
## repo branch ls
```text
Usage: libfossil repo branch ls [flags]
List branches
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--closed Show only closed branches
--all Show all branches (open and closed)
```
## repo branch new
```text
Usage: libfossil repo branch new <name> [flags]
Create new branch
Arguments:
<name> Branch name
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--from=STRING Parent version (default: tip)
-m, --message=STRING Checkin comment
--user=STRING Checkin user (default: OS username)
--nosign Do not sign the branch's check-in, even with the
clearsign setting on
```
## repo branch close
```text
Usage: libfossil repo branch close <name> [flags]
Close a branch
Arguments:
<name> Branch name to close
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--user=STRING User for control artifacts (default: OS username)
```
---
# repo uv
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-uv/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo uv <command>
Unversioned file operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo uv ls
List unversioned files
repo uv put <name> <file>
Add or update an unversioned file
repo uv get <name> [flags]
Retrieve an unversioned file
repo uv delete <name>
Delete an unversioned file (creates tombstone)
```
## repo uv ls
```text
Usage: libfossil repo uv ls
List unversioned files
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo uv put
```text
Usage: libfossil repo uv put <name> <file>
Add or update an unversioned file
Arguments:
<name> Name of the unversioned file
<file> Local file to upload
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo uv get
```text
Usage: libfossil repo uv get <name> [flags]
Retrieve an unversioned file
Arguments:
<name> Name of the unversioned file
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-o, --output=STRING Output file (default: stdout)
```
## repo uv delete
```text
Usage: libfossil repo uv delete <name>
Delete an unversioned file (creates tombstone)
Arguments:
<name> Name of the unversioned file to delete
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo schema
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-schema/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo schema <command>
Synced table schema operations
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo schema add --columns=STRING <name> [flags]
Register a new synced table
repo schema list
List registered synced tables
repo schema show <name>
Show table schema details
repo schema remove <name>
Remove a synced table registration
```
## repo schema add
```text
Usage: libfossil repo schema add --columns=STRING <name> [flags]
Register a new synced table
Arguments:
<name> Table name (without x_ prefix)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--columns=STRING Column defs: name:type[:pk],... (e.g.
peer_id:text:pk,addr:text)
--conflict="mtime-wins" Conflict strategy
```
## repo schema list
```text
Usage: libfossil repo schema list
List registered synced tables
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo schema show
```text
Usage: libfossil repo schema show <name>
Show table schema details
Arguments:
<name> Table name (without x_ prefix)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo schema remove
```text
Usage: libfossil repo schema remove <name>
Remove a synced table registration
Arguments:
<name> Table name (without x_ prefix)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo user
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-user/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo user <command>
User management
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo user add --cap=STRING <login>
Create a new user
repo user list
List all users
repo user update --cap=STRING <login>
Update user capabilities
repo user rm <login>
Delete a user
repo user passwd <login>
Reset user password
```
## repo user add
```text
Usage: libfossil repo user add --cap=STRING <login>
Create a new user
Arguments:
<login> Username
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--cap=STRING Capability string (e.g. oi)
```
## repo user list
```text
Usage: libfossil repo user list
List all users
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo user update
```text
Usage: libfossil repo user update --cap=STRING <login>
Update user capabilities
Arguments:
<login> Username
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--cap=STRING New capability string
```
## repo user rm
```text
Usage: libfossil repo user rm <login>
Delete a user
Arguments:
<login> Username
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo user passwd
```text
Usage: libfossil repo user passwd <login>
Reset user password
Arguments:
<login> Username
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo invite
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-invite/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo invite --cap=STRING <login> [flags]
Generate invite token for a user
Arguments:
<login> Username for the invitee
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--cap=STRING Capability string (e.g. oi)
--url="" Sync URL to embed in token
--ttl=0 Token time-to-live (e.g. 24h)
```
---
# repo serve
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-serve/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo serve [flags]
Serve repository over HTTP for sync/clone
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-P, --addr="127.0.0.1:8080" Bind address as host:port
```
---
# repo submanifests
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-submanifests/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo submanifests <command>
Sub-manifest tree settings
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo submanifests enable [flags]
Write new check-ins as sub-manifest trees
repo submanifests retune --k=INT
Re-pin the partition parameter for later commits
repo submanifests disable
Write new check-ins as flat manifests again
repo submanifests status
Show the sub-manifest settings and whether trees exist
```
## repo submanifests enable
```text
Usage: libfossil repo submanifests enable [flags]
Write new check-ins as sub-manifest trees
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--k=K Partition parameter, 1..12 (default: selected from the
main-branch tip)
```
## repo submanifests retune
```text
Usage: libfossil repo submanifests retune --k=INT
Re-pin the partition parameter for later commits
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--k=INT New partition parameter, 1..12
```
## repo submanifests disable
```text
Usage: libfossil repo submanifests disable
Write new check-ins as flat manifests again
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo submanifests status
```text
Usage: libfossil repo submanifests status
Show the sub-manifest settings and whether trees exist
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# repo cone
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/repo-cone/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil repo cone <command>
Show or edit a checkout's sparse cone
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
Commands:
repo cone show [flags]
List the cone's members ("dense" when there is none)
repo cone add <paths> ... [flags]
Widen the cone, or with --not carve paths out of it
repo cone remove <paths> ... [flags]
Remove members of either polarity
repo cone set <paths> ... [flags]
Replace the cone
repo cone dense [flags]
Drop the cone and materialize every file
repo cone test <paths> ... [flags]
Classify paths against the cone and name the deciding member
repo cone store [<paths> ...] [flags]
Show or replace the repository's store cone, fetching what widening covers
repo cone deepen <checkin> [flags]
Move the store's horizon down to reach a check-in, fetching the history it
keeps
repo cone compact
Drop held blobs the store cone elides (irreversible locally)
repo cone cost <checkin>
Report what each horizon rule would hold at a check-in, from this repository
```
## repo cone show
```text
Usage: libfossil repo cone show [flags]
List the cone's members ("dense" when there is none)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-d, --dir="." Checkout directory
```
## repo cone add
```text
Usage: libfossil repo cone add <paths> ... [flags]
Widen the cone, or with --not carve paths out of it
Arguments:
<paths> ... Paths to add
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--not Add the paths as exclusions
-d, --dir="." Checkout directory
```
## repo cone remove
```text
Usage: libfossil repo cone remove <paths> ... [flags]
Remove members of either polarity
Arguments:
<paths> ... Members to remove
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
-d, --dir="." Checkout directory
```
## repo cone set
```text
Usage: libfossil repo cone set <paths> ... [flags]
Replace the cone
Arguments:
<paths> ... Inclusion members
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--not=NOT,... Exclusion members (repeatable)
-d, --dir="." Checkout directory
```
## repo cone dense
```text
Usage: libfossil repo cone dense [flags]
Drop the cone and materialize every file
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
-d, --dir="." Checkout directory
```
## repo cone test
```text
Usage: libfossil repo cone test <paths> ... [flags]
Classify paths against the cone and name the deciding member
Arguments:
<paths> ... Paths to classify
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
-q, --quiet Print nothing; report through the exit status only
-d, --dir="." Checkout directory
```
## repo cone store
```text
Usage: libfossil repo cone store [<paths> ...] [flags]
Show or replace the repository's store cone, fetching what widening covers
Arguments:
[<paths> ...] Inclusion members; none shows the store cone
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
--not=NOT,... Exclusion members (repeatable)
--dense Drop the store cone, fetching everything it elided
--horizon=STRING Elide blobs below this check-in (name, branch or
hash prefix), fetching what a deeper horizon keeps;
'repo cone cost' shows what each rule would hold
--leaves With --horizon, also hold every open leaf's ancestry
back to the check-in, for merging across live
branches offline; costly: on a repository with old
unmerged branches that is nearly the whole history
--structural With --horizon, also elide the manifests below the
check-in; the next pull fetches the origin's seed
--no-horizon Drop the horizon, keeping the path members,
and fetch what it elided
```
## repo cone deepen
```text
Usage: libfossil repo cone deepen <checkin> [flags]
Move the store's horizon down to reach a check-in, fetching the history it keeps
Arguments:
<checkin> Check-in to reach: a full hash, which may lie below the horizon,
or a name
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
--remote=STRING Required-content peer URL (default: saved
last-sync-url)
--sync-user=STRING Required-content authentication user
--sync-pass=STRING Required-content password (never saved)
--sync-private Allow recovery of private required artifacts
--timeout=10m Required-content deadline; 0 disables it
```
## repo cone compact
```text
Usage: libfossil repo cone compact
Drop held blobs the store cone elides (irreversible locally)
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
## repo cone cost
```text
Usage: libfossil repo cone cost <checkin>
Report what each horizon rule would hold at a check-in, from this repository
Arguments:
<checkin> Check-in to place the horizon at: a name, branch or hash prefix
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# version
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/cli/version/
<!-- Generated by scripts/gen-cli-docs.sh from the libfossil --help output. Do not edit; change the help text in cli/ and run make docs-gen. -->
```text
Usage: libfossil version [flags]
Print version information
Flags:
-h, --help Show context-sensitive help.
-R, --repo=STRING Path to repository file
-v, --verbose Verbose output
```
---
# Settings
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/settings/
A repository setting is one row of the `config` table in the repository file. go-libfossil reads the settings below. Some are fossil's own; the rest are extensions, and each entry says which.
Set a setting with the CLI, or with `Repo.SetConfig(key, value)` in the Go API:
```
libfossil repo -R project.fossil config set clearsign on
libfossil repo -R project.fossil config get clearsign
libfossil repo -R project.fossil config ls
```
`config set` stores the value as given and stamps it with the current time. It checks only the values noted in the entries for `hash-policy`, `horizon-history-url` and `horizon-seed-key`. A setting that is not set has no row; `config get` reports it as not found. The CLI has no command that deletes a setting.
Boolean settings are read as fossil reads them: `on`, `yes`, `true` (any case) or a nonzero number mean true; `off`, `no`, `false`, `0` mean false. Any other text gives the setting's default. The reader is [`SettingBoolean`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/setting.go#L14). Entries marked "boolean" below use it unless they say otherwise.
go-libfossil reads only the repository's own `config` table. Fossil also falls back to a per-user global configuration in `~/.fossil`; go-libfossil does not.
| Setting | Default | Read by |
| --- | --- | --- |
| [`clearsign`](#clearsign) | off | check-in and seed signing |
| [`omitsign`](#omitsign) | off | check-in and seed signing |
| [`pgp-command`](#pgp-command) | `gpg --clearsign -o ` | check-in and seed signing |
| [`horizon-seed-key`](#horizon-seed-key) | none | clone, seed verification |
| [`partial-mirror`](#partial-mirror) | off | sync server |
| [`horizon-history-url`](#horizon-history-url) | none | sync server |
| [`enable-submanifests`](#enable-submanifests) | off | commit, sync |
| [`submanifest-k`](#submanifest-k) | unset | commit, sync |
| [`submanifest-auto-retune`](#submanifest-auto-retune) | off | commit |
| [`hash-policy`](#hash-policy) | derived from content | every artifact store |
| [`case-sensitive`](#case-sensitive) | on, except macOS and Windows | CLI path matching |
| [`merge-strategy`](#merge-strategy) | `three-way` | merge |
| [`main-branch`](#main-branch) | `trunk` | branch membership, leaves |
| [`hash-digits`](#hash-digits) | 10 | hash display |
| [`allow-symlinks`](#allow-symlinks) | off | checkout, file scan |
| [`mtime-changes`](#mtime-changes) | on | checkout file scan |
| [`repo-cksum`](#repo-cksum) | on | checkout |
| [`uv-sync`](#uv-sync) | off | sync server, clone |
| [`lock-timeout`](#lock-timeout) | 60 seconds | check-in lock |
| [`forbid-delta-manifests`](#forbid-delta-manifests) | on | sync server |
The last list on this page covers internal rows that are not meant to be edited.
## clearsign
Turns on signing. When it is on, every check-in that a commit or branch creation stores is signed, and so is every horizon seed an origin mints. See [Signing](/docs/concepts/signing/).
- **Read by:** [`clearsign.FromSettings`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L84). Callers are the manifest writer ([`manifest.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/manifest.go#L487)) and the horizon seed signer ([`horizon_seedsign.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/horizon_seedsign.go#L42)).
- **Values:** boolean. Unrecognized text reads as off.
- **Default:** off. With it off, no signing happens.
- **Behaviour:** the signed text is the artifact, so a signed check-in is named by the hash of the signed bytes. If the signer fails, the commit is abandoned. `CommitOpts.NoSign` and `CheckoutCommitOpts.NoSign` store one check-in unsigned.
- **Origin:** fossil 2.28 defines `clearsign` (default off). The envelope format is in `draft-fossil-artifact-format-00` section 4.1.1. Signing horizon seeds is an extension (`draft-fossil-horizon-00` section 5.2.4).
- **Set:** `libfossil repo config set clearsign on`
- **Code:** [`SettingClearsign`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L33), [`libfossil.SettingClearsign`](https://github.com/danmestas/go-libfossil/blob/main/signing.go#L13)
## omitsign
Turns signing off again, even when `clearsign` is on.
- **Read by:** [`clearsign.FromSettings`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L84), after `clearsign`.
- **Values:** boolean. Unrecognized text reads as off.
- **Default:** off.
- **Origin:** fossil's legacy setting. It is not in the list printed by `fossil settings` in 2.28. go-libfossil reads it so a repository that carries it keeps its meaning. No draft specifies it.
- **Set:** `libfossil repo config set omitsign on`
- **Code:** [`SettingOmitsign`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L34)
## pgp-command
The command that signs. Used only when signing is on.
- **Read by:** [`clearsign.FromSettings`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L84), which builds the `Signer`.
- **Values:** a shell command. The command runs through the shell, so `~` and environment variables expand. A command whose first word starts with `ssh` is run as `COMMAND INFILE`; it must write a detached `INFILE.sig`, and go-libfossil wraps it in fossil's SSH envelope. Any other command is run as `COMMAND OUTFILE INFILE` and must write a clear-signed `INFILE` to `OUTFILE`. A value that reads as false (`off`, `no`, `false`, `0`) turns signing off. An empty value uses the default.
- **Default:** `gpg --clearsign -o `.
- **SSH signing:** set it to `ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519`. The namespace must be `fossilscm`, or a clone cannot verify the signature.
- **Origin:** fossil 2.28 defines `pgp-command`. Go-libfossil follows fossil's `src/clearsign.c` contract, so one setting signs with either tool.
- **Set:** `libfossil repo config set pgp-command 'ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519'`
- **Code:** [`SettingPGPCommand`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L35), [`libfossil.SettingPGPCommand`](https://github.com/danmestas/go-libfossil/blob/main/signing.go#L25)
## horizon-seed-key
The public key a clone uses to verify the horizon seeds its origin sends. See [Signing](/docs/concepts/signing/) and [Horizons](/docs/concepts/horizons/).
- **Read by:** [`clearsign.SeedKey`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L202), called from the seed code ([`seed/sign.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/horizon/seed/sign.go#L25)) and the seed signer.
- **Values:** an SSH public key line (`ssh-ed25519 AAAA... comment`), checked in process, or an OpenPGP fingerprint of 40 or 64 hex digits (spaces allowed), checked by `gpg` against the user's keyring. `Repo.SetConfig` and `config set` refuse any other non-empty value. An empty value counts as no key.
- **Default:** none. With no key, a clone accepts an unsigned seed.
- **Behaviour:** with a key set, a seed that is unsigned or not signed by that key is discarded and the clone falls back to the content horizon.
- **Origin:** go-libfossil extension, specified in `draft-fossil-horizon-00` section 5.2.4. It belongs to the clone; an origin never sends it.
- **Set:** `libfossil repo config set horizon-seed-key 'ssh-ed25519 AAAA...'`, or `CloneOpts.SeedKey` at clone time ([`keepSeedKey`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/clone.go#L313)).
- **Code:** [`SettingSeedKey`](https://github.com/danmestas/go-libfossil/blob/main/internal/clearsign/clearsign.go#L36), [`libfossil.SettingHorizonSeedKey`](https://github.com/danmestas/go-libfossil/blob/main/signing.go#L35)
## partial-mirror
Lets a sparse store serve clones that its cone does not cover. See [Sparse cones](/docs/concepts/sparse-cones/).
- **Read by:** [`handler.servesPartialMirror`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/sparse_policy.go#L25), for clone requests. It covers every serving surface: `HandleSync`, `XferHandler` and `ServeHTTP`.
- **Values:** boolean. Unrecognized text reads as off. The `PartialMirror` serve option overrides the row and turns serving on ([`handler.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/handler.go#L175)).
- **Default:** off. A sparse store then refuses such a clone with one error card and no content, because the clone would get elided phantoms it must resolve elsewhere.
- **Origin:** go-libfossil extension. `draft-fossil-sparse-cone-00` section 5.3 says a server should refuse unless "explicitly configured as a partial mirror". Fossil has no such setting.
- **Set:** `libfossil repo config set partial-mirror on`
- **Code:** [`SettingPartialMirror`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/sparse_policy.go#L21), [`libfossil.SettingPartialMirror`](https://github.com/danmestas/go-libfossil/blob/main/repo_sparse.go#L19)
## horizon-history-url
The address of an interface, outside the sync protocol, where history below a horizon can be queried. An origin appends it to the `horizon-served` pragma. See [Horizons](/docs/concepts/horizons/).
- **Read by:** [`historyURL`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/sparse.go#L175) in the sync server. Clients report it as `CloneResult.HorizonHistoryURL` and `SyncResult.HorizonHistoryURL`.
- **Values:** one `http` or `https` URL with a host, no white space or control bytes, no credentials, at most 2048 bytes. [`CheckHistoryURL`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/setting.go#L79) enforces this, and `SetConfig` refuses anything else. An empty value names none. A bad value that got into the table some other way is treated as unset when serving.
- **Default:** none.
- **Origin:** go-libfossil extension, `draft-fossil-horizon-00` section 6.2.5.
- **Set:** `libfossil repo config set horizon-history-url https://history.example/q`
- **Code:** [`SettingHorizonHistoryURL`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/setting.go#L70), [`libfossil.SettingHorizonHistoryURL`](https://github.com/danmestas/go-libfossil/blob/main/repo_sparse.go#L28)
## enable-submanifests
Makes new commits write tree manifests (sub-manifests) instead of flat ones. See [Sub-manifests](/docs/concepts/sub-manifests/).
- **Read by:** [`readSubmanifestSettings`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L80) at commit ([`emissionK`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L114)); [`enableSubmanifests`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/submanifest.go#L151) in the sync server, where it decides the capability pragmas; and the required-content state digest.
- **Values:** `on`, `off`, `1`, `0`, `yes`, `no`, `true`, `false` (any case). Any other text reads as off. A commit also emits no tree in a sync session where the server sent `avoid-submanifests`.
- **Default:** off.
- **Behaviour:** once a tree manifest exists, peers that do not announce sub-manifest support (every fossil) are refused artifacts that carry an `S` card. Turning the setting off later does not retire trees already written.
- **Config exchange:** it is a `/project` setting, so clone and pull carry it. A received set is applied all or none: a bad value, or `enable-submanifests` on with no `submanifest-k` from 1 to 12, leaves all three as they were ([`apply`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/submanifest.go#L260)).
- **Origin:** go-libfossil and zit extension. No fossil release has it. Specified in `draft-fossil-submanifests-00` sections 6.3 and 8.1.
- **Set:** prefer `libfossil repo submanifests enable [--k N]`. It pins `submanifest-k` first and prints the warning about what cannot be undone ([`EnableSubmanifests`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L153)). `libfossil repo submanifests disable` turns it off. `config set enable-submanifests on` works but skips those checks.
- **Code:** [`SettingEnableSubmanifests`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L31)
## submanifest-k
The partition parameter k that a commit uses to build the tree.
- **Read by:** [`readSubmanifestSettings`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L80), then `emissionK` at commit.
- **Values:** a decimal integer from 1 to 12. Anything else is not a valid pin. A commit with `enable-submanifests` on and no valid pin logs a warning and writes a flat manifest.
- **Default:** unset.
- **Behaviour:** a valid pin takes precedence over an explicit k on enable; changing it is a re-tune.
- **Origin:** extension, `draft-fossil-submanifests-00` sections 6.3 and 8.1. A `/project` setting.
- **Set:** `libfossil repo submanifests enable --k N` for the first pin, `libfossil repo submanifests retune --k N` to change it, `libfossil repo submanifests status` to read all three. `config set submanifest-k N` stores any text without checking the range.
- **Code:** [`SettingSubmanifestK`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L32)
## submanifest-auto-retune
Allows a commit to re-pin `submanifest-k` by itself when the analyzed optimum has drifted.
- **Read by:** [`checkinTree.retune`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L443), after a commit that wrote a tree.
- **Values:** same boolean spellings as `enable-submanifests`. Any other text reads as off.
- **Default:** off. With it off, a drift only logs an advisory.
- **Behaviour:** the re-tune runs after the commit is durable, in its own transaction. If the pin changed meanwhile, nothing is written. A failure is logged and the commit stands.
- **Origin:** extension, `draft-fossil-submanifests-00` section 6.4 (a project-scope boolean, default false, never on by default). A `/project` setting.
- **Set:** `libfossil repo config set submanifest-auto-retune on`. There is no dedicated command.
- **Code:** [`SettingAutoRetune`](https://github.com/danmestas/go-libfossil/blob/main/internal/manifest/submanifest_write.go#L33)
## hash-policy
Which hash names new artifacts: SHA-1 or SHA3-256.
- **Read by:** [`hash.NamingFor`](https://github.com/danmestas/go-libfossil/blob/main/internal/hash/policy.go#L116) (through `policyFor`) before every artifact store; [`PromoteFor`](https://github.com/danmestas/go-libfossil/blob/main/internal/hash/policy.go#L160) rewrites it.
- **Stored form:** the ordinal, 0 to 4: `0` sha1, `1` auto, `2` sha3, `3` sha3-only, `4` shun-sha1. A stored value outside 0 to 4, or not a number, is an error, not a reason to fall back.
- **Default when no row exists:** `sha3` if the repository holds any SHA3-named artifact or no SHA-1 one; otherwise `auto`. It never derives `shun-sha1`. A new repository is created with `hash-policy` = 2. A clone removes the row so that it adopts its source's policy ([`clone.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/clone.go#L303)).
- **Behaviour:** under `auto`, storing the first SHA3-named artifact promotes the row to `sha3`. Under `sha3-only` and `shun-sha1` legacy names are not reused.
- **Origin:** fossil defines the policy (`fossil hash-policy`, stored in the `config` table; it is not in `fossil settings`). Specified in `draft-fossil-artifact-format-00` section 7. It is a `/project` setting in config exchange.
- **Set:** in Go, `Repo.SetHashPolicy("sha3")` ([`repo_admin.go`](https://github.com/danmestas/go-libfossil/blob/main/repo_admin.go#L102)); names are matched exactly and case-sensitively, and `auto` in a repository that already holds a SHA3 artifact stores `sha3`. The CLI has no policy command. `config set hash-policy 2` takes the ordinal; `config set hash-policy sha3` is refused.
- **Code:** [`SetConfig` check](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/repo.go#L302), [`SetHashPolicy`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/repo.go#L331), [seeded value](https://github.com/danmestas/go-libfossil/blob/main/db/schema.go#L348)
## case-sensitive
Whether file names that differ only in case are different files.
- **Read by:** [`Repo.FilenamesCaseSensitive`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/setting.go#L57). The only caller is the CLI's PATH matching ([`newRepoPaths`](https://github.com/danmestas/go-libfossil/blob/main/cli/pathmatch.go#L19)), used by `repo cat`, `repo diff` and `repo log`. When it is off, names compare with ASCII case folding.
- **Values:** boolean.
- **Default:** off on macOS and Windows, on elsewhere, as fossil's platform default.
- **Origin:** fossil 2.28 defines `case-sensitive`. No draft specifies it.
- **Set:** `libfossil repo config set case-sensitive off`
- **Code:** [`setting.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/setting.go#L57)
## merge-strategy
The merge strategy used for files that no `.libfossil-merge` rule matches.
- **Read by:** [`merge.LoadResolver`](https://github.com/danmestas/go-libfossil/blob/main/internal/merge/resolve.go#L28), called by `Checkout.Merge` ([`merge.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/checkout/merge.go#L507)).
- **Values:** the name of a registered strategy: `three-way`, `binary`, `last-writer-wins` or `conflict-fork`. An empty value is ignored. An unknown name is not checked when the setting is stored; the merge fails with `unknown merge strategy "NAME" for FILE`.
- **Default:** `three-way`.
- **Precedence:** `libfossil repo merge --strategy NAME` overrides everything. Without it, the first matching glob in `.libfossil-merge` at the checked-out version wins, then this setting.
- **Origin:** go-libfossil extension. Fossil has no such setting and no draft specifies it.
- **Set:** `libfossil repo config set merge-strategy binary`
- **Code:** [`resolve.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/merge/resolve.go#L35)
## main-branch
The name of the default branch, for check-ins with no active branch tag.
- **Read by:** [`repo.MainBranch`](https://github.com/danmestas/go-libfossil/blob/main/internal/repo/mainbranch.go#L21), and the SQL fragments in [`leaf.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/leaf/leaf.go#L61) and [`fork.go`](https://github.com/danmestas/go-libfossil/blob/main/internal/checkout/fork.go#L139).
- **Values:** a branch name. An empty value reads as unset.
- **Default:** `trunk`.
- **Origin:** fossil 2.28 defines `main-branch`. `draft-fossil-repo-state-00` section 6.1 requires readers not to assume `trunk` when it is set. Reading an empty value as unset departs from the draft and from fossil.
- **Set:** `libfossil repo config set main-branch main`
## hash-digits
How many hash characters fossil's `%S` conversion prints.
- **Read by:** [`fsltype.HashDigits`](https://github.com/danmestas/go-libfossil/blob/main/internal/fsltype/printf.go#L23).
- **Values:** an integer, clamped to 6 through 64. Zero reads as unset. The URL length is the value plus 6, at least 16 and at most 64.
- **Default:** 10.
- **Origin:** fossil 2.28 defines `hash-digits`. No draft specifies it.
- **Set:** `libfossil repo config set hash-digits 12`
## allow-symlinks
Whether a symbolic link on disk is seen as itself.
- **Read by:** [`vfile.OpenDisk`](https://github.com/danmestas/go-libfossil/blob/main/internal/vfile/disk.go#L70), when a checkout opens its disk view.
- **Values:** boolean.
- **Default:** off. A link is then read as a file holding the link's target name, as fossil does.
- **Origin:** fossil 2.28 defines `allow-symlinks`. No draft specifies it.
- **Set:** `libfossil repo config set allow-symlinks on`
## mtime-changes
Whether a checkout file scan may trust file modification times.
- **Read by:** [`newScanPolicy`](https://github.com/danmestas/go-libfossil/blob/main/internal/checkout/vfile.go#L310). A hash scan never trusts mtimes, whatever this says.
- **Values:** boolean.
- **Default:** on. With it off, every scan hashes the file.
- **Origin:** fossil 2.28 defines `mtime-changes`. No draft specifies it.
- **Set:** `libfossil repo config set mtime-changes off`
## repo-cksum
Whether a checkout verifies the manifest's `R` card.
- **Read by:** [`checkRCard`](https://github.com/danmestas/go-libfossil/blob/main/internal/checkout/extract.go#L132), after extracting a version.
- **Values:** boolean.
- **Default:** on. A disagreement is a warning, not an error. A sparse store skips the check.
- **Origin:** fossil 2.28 defines `repo-cksum`. No draft specifies it.
- **Set:** `libfossil repo config set repo-cksum off`
## uv-sync
Whether a clone also receives the unversioned-file catalog.
- **Read by:** [`handler.sendCloneUVCatalog`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/handler_uv.go#L50), in the sync server, for a requester with read access.
- **Values:** `1`, `on`, `yes`, `true` (any case) mean on. Anything else, including an unrecognized number, means off.
- **Default:** off.
- **Origin:** fossil 2.28 defines `uv-sync`. No draft cited here specifies it.
- **Set:** `libfossil repo config set uv-sync on`
## lock-timeout
How long a check-in lock (`ci-lock`) stays valid, in seconds.
- **Read by:** [`lockTimeout`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/ckin_lock.go#L21), in the sync server.
- **Values:** an integer, read by SQLite's integer conversion, so text that is not a number reads as 0. A value of 0 or less makes every lock stale at the next `ci-lock`, as in fossil.
- **Default:** 60.
- **Origin:** fossil 2.28 defines `lock-timeout`. `draft-fossil-sync-protocol-00` section 9.4.
- **Set:** `libfossil repo config set lock-timeout 120`
## forbid-delta-manifests
Whether the server tells clients not to send delta manifests (the `avoid-delta-manifests` pragma).
- **Read by:** [`forbidDeltaManifests`](https://github.com/danmestas/go-libfossil/blob/main/internal/sync/ckin_lock.go#L36), in the sync server.
- **Values:** boolean. A missing or NULL row is on, and text that is neither true nor false keeps on.
- **Default:** on.
- **Origin:** fossil 2.28 defines `forbid-delta-manifests` with a default of off. go-libfossil follows `draft-fossil-sync-protocol-00` section 9.4 (fossil 2.29's default), so against a fossil 2.28 server's own default the two differ unless the row is set. It is a `/project` setting in config exchange.
- **Set:** `libfossil repo config set forbid-delta-manifests off`
## Internal rows
These rows are bookkeeping. Do not edit them. Some are written by sync or by `repo clone`, and some are read only by internal code.
- `project-code`, `server-code`: the repository's identities, set at creation or taken from the origin on clone. Fossil defines them.
- `aux-schema`, `content-schema`: schema versions, set at creation. Fossil defines them.
- `last-sync-url`: the default peer, written by `repo clone` and read by commands that take no URL. Fossil defines it.
- `seen-submanifest`: set once the repository stores an artifact with an `S` card, never cleared, never synced. Extension (`draft-fossil-submanifests-00` section 8.1).
- `horizon-cursor:ORIGIN` and `horizon-rekept`: horizon sync state. Extension.
- `ci-lock-HASH` and `libfossil-ci-lock-*`: check-in lock rows. The first form is fossil's.
- `uv-hash`: cached hash of the unversioned catalog.
- `invite-expire:LOGIN`: when a login's invite expires. go-libfossil only.
- `link:URL`: links received in share-links sync.
Other rows that sync carries as configuration, such as `project-name`, `ignore-glob` or the skin settings, pass through the `config` table without go-libfossil acting on them.
See the [CLI reference](/docs/reference/cli/) for the commands above.
---
# Conformance
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/reference/conformance/
go-libfossil is checked against the Internet-Drafts that specify Fossil's formats and protocol, and the drafts for the extensions it shares with zit. The drafts are pinned in [`conformance/rfcs/`](https://github.com/danmestas/go-libfossil/tree/main/conformance/rfcs). Each has a table of requirements in [`conformance/requirements/`](https://github.com/danmestas/go-libfossil/tree/main/conformance/requirements), written from the draft text, and test cases that name the requirement they exercise.
`TestCoverage` derives each requirement's status from its cases; nothing is recorded by hand:
- **covered**: every case conforms.
- **partial**: the cases conform, and the table row says what they leave out (shown under the requirement).
- **deviation**: a case documents a deliberate difference, with its reason.
- **failing**: a case is known to fail and names the issue tracking the fix. It is skipped, and fails once it passes until the mark is removed.
- **gap**: no case exercises the requirement.
What counts as correct, in order: the draft text; then fossil itself, run on the same input, where the draft is silent. The suites of zit and libfossil inform which cases to write. The tables below are generated from a run of the suite (`make docs-gen`), and CI fails when they are out of date. To reproduce them:
```sh
CONFORMANCE_REPORT=report.md go test ./conformance -run '^TestCoverage$' -count=1
```
---
# Examples
URL: https://libfossil-docs.daniel-mestas.workers.dev/docs/examples/
Runnable examples live in the repo. Each is a self-contained `main.go` you can clone and run.
## embed-repo-api
Minimal example of embedding libfossil as a library in a Go application. Walks the basic repo lifecycle — register the default pure-Go SQLite driver via blank import, create a `.fossil` in a temp directory, close, re-open, write a commit, read the timeline, list files, clean up.
→ [`examples/embed-repo-api`](https://github.com/danmestas/go-libfossil/tree/main/examples/embed-repo-api)
## wasm
Building libfossil for a generic WASI Preview 1 target. The compiled `.wasm` is not tied to any specific runtime and runs under `wasmtime`, `wazero`, or any WASI P1 host. Uses the [`ncruces` driver](/docs/reference/sdk/db/driver/ncruces/) — the default `modernc` driver pulls in syscalls (`pthread`, etc.) that WASI doesn't provide.
→ [`examples/wasm`](https://github.com/danmestas/go-libfossil/tree/main/examples/wasm)