This project implements some of Beagle SCM functionality for regular git repos. The work is ongoing, so far it can do:
- CRDT merges (use
bee installto add a hook to a git repo), - TUI repo browser (use
bee ./fileto open), - HTML browser (use
bee http --port 8888to run, then openhttp://localhost:8888/myprojectin a browser), - token-level diffs (may start with
bee logorhttp://localhost:8888/myproject/logthen click around), - permalink support, version-aware links that survive edits
(e.g.
index/perma.js:6:ur, see them in the pager/browser,bee seefor CLI use, commit hook orbe mintto create)
Reproducing Beagle's smooth worktree workflows turned difficult so far, as git submodule and git worktree implementations are rather abrasive.
Build: bundle with the quickjab runtime for a standalone binary. That carries dog/ (libdog), dog/abc/ (libabc) and test/ (the jab-shared API suite) as submodules:
cmake -S <quickjab> -B build -GNinja \
-DJAB_JSRC=<js bundle tree> -DQUICKJAB_JSRC_PACK=ON
ninja -C build quickjab
Usage — a terminal with no flag pages coloured hunks; otherwise one mode flag
picks the sink, --plain (also what a pipe defaults to), --color, --html:
bee— in a git repo: index it, open thelistbrowser; elsewhere asbee <path>bee <path>...— page files/dirs off the filesystembee index [<repo>]— build/refresh<repo>/.git/be/; lazy, fully derived; BOTH passes, the commit walk and the tip-blob link scan, each off its own mark, both on the one summary line- every INITIALISED submodule is indexed too, depth-first; an uninitialised one is skipped in words
- inside a LINKED WORKTREE it registers the ORIGINAL — one repository is one line, and it says which
bee lindex [<target>]— backlink suspects; lazy, tip blobs only- bare: bring the LINK rows up to the tip, this repo only
<target>: the paths that may link to a file or a ticket code, looked up in EVERY repo of~/.config/bee/repos(read-only) and printed repo-qualified, the local repo first
bee log [<n>] [<hex>|<path>][?<rev>]— commit log, newest first; off-mainline rows grey- bare: the checked-out tip's ancestry;
<n>caps the rows,0= all <hex>: that commit's ancestry<path>: the file's revisions?<rev>: a branch, tag or hexlet names the tip —log ?main,log f.c?v2<sub>/<path>: the SUBMODULE's own history, its rows opening in the sub- a ticket code in a summary is a link, like any other reference
- bare: the checked-out tip's ancestry;
bee commit [<hex>]— one commit, header + message; tree/parent hashes are linksbee diff [<hex> [<hex>]|<path>]— the token-level diff: one weave per path, seeded at the two revisions' merge base, every token naming its own commit- bare: worktree vs HEAD
<hex>: that commit vs its first parent<hex> <hex>: any two revisions, rooted at their merge base<path>: that file/dir only
bee list [<path>][?<rev>]— dir browser: marker, name, last commit, agebee cat <path>[?<rev>]— the file's own bytes, syntax-paintedbee tree [<hex>|<path>][?<rev>]— raw git-tree rows,..row when descendedbee blob <hexlet>— a blob by object namebee see [-C<n>] <ref>...— the chunk each reference names, two lines of context each way; the only CLI door onto a permalink- every shape
door.jsresolves: permalink, path, partial, ticket code, pocket page, another registered repo - one hunk per ref, in the order given; a miss names the repos searched, an ambiguity shows the chooser, neither ends the batch
- every shape
bee http [--port <n>]— the same views over HTTP on localhost:8034, read-only, EVERY registered repo/<repo>/<path>is the file itself,/<repo>/<verb>/<path>a named view; a repo-less URL 301s to the prefixed form- a
.mdURL renders as a page, links resolved;.mkdstays painted - an
.rstURL renders the reST subset; directives and tables show literal /<repo>/raw/<path>is the painted source, and each view links to the other/<repo>/bytes/<path>[?<rev>]ships the file's raw bytes; a rendered image points there- a SUBMODULE is served through its parent (
/quickjab/dog/abc/TCP.c), never under a name of its own
bee install [<repo>]— wire bee as the repo's git merge driver and pre-commit hook, list it in~/.config/bee/repos, index it- a LINKED WORKTREE is refused: a repo is known by its path (
bee indexredirects to the original instead) - a SUBMODULE is an ordinary repo: each initialised one is registered, indexed and lindexed too
- a LINKED WORKTREE is refused: a repo is known by its path (
bee hook [<repo>]— the pre-commit pass: freshfile:line(:col)refs in the staged text becomefile:LINE:HASHLETpermalinks, re-stagedbee mint [--dry-run] <file>...— the same upgrade for refs that ALREADY landed transient, in the working copy only; the hook cannot reach those- the file list names the CARRIERS: refs written in them, pointing anywhere; a target not listed must be clean, or it is refused
- everything left alone is reported, one line per ref — unresolved, ambiguous, past the end, on a link cycle
bee merge <base> <ours> <theirs> [-o <out>] [-p <path>]— CRDT 3-way file merge- clean: merged bytes over
<ours>(or<out>), exit 0 - conflict: markerless weave, exit 1
- binary/oversize: falls back to
git merge-file
- clean: merged bytes over
bee chat [dir] [outdir]— Claude session logs to StrictMark pages, append-only reruns