Artifact c6f8ea61d489fc5b16b36aef79f80e9f8f9fa3862ff034c187e6997d10493b0e:
- File
docs/site/content/docs/get-started/first-sync.md
— part of check-in
[41dfd5c149]
at
2026-10-23 21:12:44
on branch main
— docs: landing page from the approved design, docs in its typography
The home page renders its hero figure, conformance table, version and footer from the generated data and site params. Docs pages keep Hextra with Fraunces, Inter and JetBrains Mono and rust as the accent in both themes. Add the get-started pages (install, CLI quickstart, embed in Go, first sync), the conformance reference rendered from data, and point the nav, README and old links at the new layout. (user: [email protected], size: 3584) [annotate] [blame] [check-ins using] [more...]
title: First sync
weight: 40
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 explains the protocol.
Serve a repository
libfossil -R notes.fossil repo serve
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:
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:
libfossil repo clone http://127.0.0.1:8080 copy.fossil
fossil clone http://127.0.0.1:8080 copy2.fossil
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 and Horizons.
Clone, commit, push and pull from 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)
}
NOTES_PASSWORD=... go run .
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:
libfossil -R notes.fossil repo timeline
fb5af4c078 2026-10-23 21:02 bo add a todo
ee68ff62c5 2026-10-23 21:02 ana first notes
Next
- Sync: the cards and rounds behind these calls.
- Production patterns: contexts, errors and telemetry for a long-running service.
- Signing: signed check-ins and signed horizon seeds.