Changelog¶
Changes are grouped by release. Unreleased describes work on the development branch. Older entries describe their release's commands and behavior; use the current command reference for today's syntax and Project for support policy.
v0.16.1 — 2026-09-14¶
Fixed¶
ff pushof a branch that is not checked out no longer overwrites that branch's parked work with the current checkout's tree. Work already affected is recovered from a retained pre-push capture.
v0.16.0 — 2026-09-14¶
Added¶
fufu.autoFetch: eligible commands refresh tracking refs at most once per cadence (10mby default), with a three-second fetch deadline and terminal prompts disabled. External helpers can still prompt, and some transport handshakes can exceed the deadline.falseorCIdisables automatic fetch;ff pulland explicit--fetchremain available.ff doctorreports the last refresh.- Global
--fetchand--no-fetch: force or skip a supported fetch; unsupported--fetchreturnsfetch/not-here. ff branch --prune: deletes local branches whose remote copy is gone, preserving branches with unique work, the current branch, branches checked out elsewhere, and held rewrites. Child branches are redirected to the deleted branch's base.--dry-runpreviews deletion; capture, auto-fetch, and maintenance can still run.fufu.pruneGone: enables the same pruning during ff pull; defaults tofalse.- Seen records at
refs/fufu/seen/<branch>: reporting pulls, successfulff pushsends,ff switchcreating a remote-tracking branch, andff clonerecord the observed remote tip. Replacing or deleting remote history requires seen/tracking agreement; fast-forward pushes can proceed without it.
Changed¶
ff op trimreplacesff trim; the old spelling remains an unlisted alias and reportsop trimin JSON.- ff pull uses the global
--no-fetchflag with its existing meaning. - Fetches prune deleted remote-tracking refs. Doctor requests a fetch on every run when fetching is enabled.
ff undoafter ff branch -d restores the branch's timeline pointer, matchingff fold.- Documentation and command help explain defaults, recovery scope, IDs, hooks, and network side effects; a dedicated revisions reference covers addressing. Historical design and performance evidence are labeled separately from current usage.
Fixed¶
- Remote-history replacement checks use the seen record so an editor fetch,
ff git fetch, or ff pull --dry-run cannot silently authorize overwriting newly fetched work.
Known issues¶
- Seen records are absent in older repositories. A first fast-forward push records one; a replacement push without one returns
push/unseen. A reporting pull records the observed tip. - Named off-branch pushes send the requested tips but can record the current checkout's tree as the target branches' open state. Switching there can resume unintended deletions; see the stacked-branch guide for recovery and the current-branch workaround.
v0.15.0 — 2026-09-12¶
Added¶
ff switch <branch>takes a branch only a remote holds, minting the local branch under that name and tracking it, the waygit switchdoes; a name two remotes hold isbranch/ambiguous.- Bare
-bonff switch:ff switch main -bforks main onto an anonymous branch. --from <revset>onff absorband--into <rev>onff lift, with-mand--no-verifyon both: a contiguous run of commits moves into any commit on the branch's line, or the open change.ff absorb --from HEAD~2..squashes two commits into the third;ff lift --from HEAD~3 --into HEADmoves a commit's content up the stack. A source the move empties is dropped and named.
Changed¶
- The open change is a commit, written at
refs/fufu/open/<branch>by every capture of a dirty tree. The@row's sha onff log,ff status, andff showis that commit's, andff commitmoves the branch onto it, minting a new one only where it must (signing, a partial close, a hook that changed the tree or message) and saying so on are-minted:line. - The park is the open commit.
ff switchand its kin leave a dirty tree's change at that ref,git stash listno longer showsfufu: wip on <branch>rows, and a park made by an earlier fufu folds into the open commit on the first arrival there. - Staged state is not carried across a park: a staged hunk comes back as an unstaged edit.
- Arriving on a branch whose tip moved under its park replays the open commit onto the new tip; a replay that conflicts holds the branch (exit 3), and
ff resolvelays the change into the working copy. @^isHEADand@~nisHEAD~(n-1), so@~3..@is two commits plus the open change.ff startandff neware spellings offf switch, and every spelling is one operation: find the branch, else mint it.ff start <branch>continues the branch;-bforks.ff start @andff branch <name> @carry a copy of the open change onto the new branch while the branch left behind keeps its own;ff start @was refused.ff absorbandff liftare one move and say the same thing:moved <n> file(s) from <sources> into <target>, then the restack and the drops.--jsoncarries the report undermove.- A dirty tree with no
user.namerefuses to switch away, since no open commit could stand as its park. ff hookandff unhookremove the MCP server registration an earlier fufu wrote forclaude,codex,cursor, andgemini.--jsonrenames:arrival.stategainsheldandlandedand losesstill_parked;openreplacesstashunderrestored,held,landed, andparked;open_leftreplacesparked_demoted;ff done --abandon'sleftreplacesstashed.
Removed¶
ff mcpand its registration in the four agent clients.- The declared extension side:
ff extension, the registry, the--ff-manifest,--ff-tools, and--ff-skillhandshakes, and theextension/*error ids.ff <name>still runsff-<name>from PATH. - The operation route:
route()in the op revset and therouteline and key onff op show. ff start's own help page and JSON envelope;ff help startis switch's page, and--jsonunder every spelling isswitch. TheabsorbandliftJSON keys; both verbs carrymove.
Fixed¶
- A range revset —
x..,x..y— no longer leaks a ref tip that shares a commit time with the hidden commit. ff pull's native fetch no longer opens every linked worktree once per advertised ref; gix upgraded to 0.87.1 (#10).
v0.14.0 — 2026-09-10¶
Added¶
ff fold [<target>] [--stay]lands the branch you stand on into another, trunk when none is named: its commits replay onto the target's tip, the target fast-forwards, the branch goes to trash, and the worktree moves to the target with the open change still open, one undoable operation with the branches above re-aimed at the target.--staykeeps the branch on the result, and advances a target another worktree holds. A replay that would conflict isfold/conflictand changes nothing.--jsoncarries the report asfold.ff branch <name> [<rev>]creates a branch at<rev>, trunk by default, without switching, as one undoable operation. A branch name as<rev>is recorded as the parent, and@is the commit under the open change.--jsoncarries it asbranch create.ff evolog <rev>drills into a change: every operation, on any worktree's chain, that produced a commit carrying its change id, then the captures behind the close.--jsoncarrieschange_id,commit,operations, andsnapshots.
Changed¶
- The letters column on
ff log,ff status, the map, andff showis a change id, the identity a commit keeps through every rewrite fufu performs, in place of the op anchor.ff commitwrites it as jj'schange-idheader, and a commit made outside fufu derives one from its sha.--jsoncarrieschange_id. - A letters token in a revision slot is a change id or a unique prefix of one; an ambiguous prefix is
usage/revset-ambiguous, and a change standing on more than one visible commit isusage/revset-divergent. Operation and capture ids are hex, twelve characters, like jj's, onff op log,ff evolog,ff history,ff undo,--at-op, and everyidthe JSON surface carries for an operation. A change id in an op slot isusage/rev-in-op-position, and an op id in a revision slot isusage/op-in-rev-position. ff switch <change id>redirects toff startat that commit, the wayff switch <sha>does.ff restackand the cascade drop a commit whose change id the base already holds:dropped … — superseded by <sha> in the base. JSONdroppedentries gainreasonand, undersuperseded,by.- A branch created outside fufu records the branch it was cut from as its base when that is certain: its tip is one other non-trunk branch's tip, or git's reflog names it. The absorb line says
forked from <branch>, andff undotakes the record back. - A git upstream under another local branch's name, or trunk's, is the branch's base rather than its shared copy:
ff statusshows it on the base axis,ff branchshows no copy, and thebranch/aliased-copyrefusal goes. ff branch,ff worktree, andff extensiontake flags, not subcommands: bare lists, a positional creates or adds,-d/--deletedeletes or removes.--at,--at-op, and--allare the list's alone.ff git mergeruns underfufu.gitPolicy strict, the wayff git tagdoes, and the coaching line forgit mergenamesff pullandff git mergein place offf restack --onto.
Removed¶
id_lettersfromff status --jsonandff log --json;idis the operation's hex, and what--at-opreads.- The
list,create,delete,add, andremovesubcommand spellings underff branch,ff worktree, andff extension, and theusage/unknown-subcommandredirect fromff branch <name>toff describe -b.
Fixed¶
ff commit -b <fresh>from a named branch no longer leaves its pending description on the branch it left.ff restack --ontotrims the replay by the target's reflog, not only the recorded base's, so a branch cut outside fufu no longer replays a stale copy of a commit its base has since rewritten. (#5)ff pushon a branch whose upstream is another branch's tracking ref creates the branch's own copy and records the upstream as its base, instead of pushing to that ref under a lease. (#7)
Known issues¶
- A rebase or cherry-pick run outside fufu drops the
change-idheader, and the commit comes back with a derived id. jj has the same limitation. - After
ff undothenff redoof a partial close, the remainder can carry a different change id than it did between them.
v0.13.0 — 2026-09-08¶
Added¶
ff pull <branch>...andff push <branch>...act on the branches named, from wherever you stand: a pull brings each with the local bases beneath it, a push sends each under its own lease, and a lease the remote refuses is that branch's alone. A name resolves the wayff restackresolves one.ff pull --allis every local branch; push has no--all.ff pull --dry-run(-n) says which branches would fast-forward, replay, hold, or be skipped, and writes nothing but remote-tracking refs;--no-fetchbeside it reads what you already have. The exit is 3 when a branch would hold.ff status --jsoncarries the orientation an agent asks for first:root,worktree,basewith the count above it,remote, andlast_op.- Every operation carries its route,
shellortool, in its trailer: onff op showandff op log --json, and as theroute()filter in the op log's set language. - Every
ffinvocation readsCLAUDE_CODE_SESSION_IDwhen neither--sessionnorFF_SESSIONis set, so a shell verb under Claude Code carries the session its hook captures do;ff mcpreads it once at start. - jj's names as aliases:
ff bookmark,ff workspace,ff squash, andff rebaserunff branch,ff worktree,ff absorb, andff restack.ff abandonandff splitanswer withusage/foreign-verbnaming the moves that cover them. Every alias shows onff --help. - The manifest's
updateandbuildfields.ff updatewalks every declared extension after fufu by the rules it applies to itself, the passive release notice covers anofficialbuild with a github.comreleasesrecipe, andff extension addsays howff updatewill answer for the extension.update.jsoncarriesextensions. ff hook -urefreshes what is wired and adds nothing: every declared extension's manifest is re-asked, then the install re-run for every slug already wired.install.shandinstall.ps1run it after placing the binary.ff hook --jsoncarriesextensions.ff doctor's Extensions floor reports a declared extension whose binary has moved past its record as that extension's own drift row, withff extension add <name>as the repair.
Changed¶
ff syncisff pullandff publishisff push; the old spellings stay as visible aliases. The error ids undersync/andpublish/arepull/andpush/, and the old ids resolve nowhere,ff explainincluded. The operation log, the JSON envelope'scmdanddatakey, and the countsff statusprints (N to pull,N to push) follow.- Bare
ff pullis the branch you stand on and the local bases beneath it, rather than every local branch;ff pull --allis the whole-repository run. ff mcpserves seven typed tools,status,pull,push,undo,redo,explain, andhelp, each taking the verb's own flags as fields and acwd, in place of the onefftool and its args array; every other verb is the shell.isErrorfollows the envelope rather than the exit code, and every result carries the child's exit in_meta.exit. The briefing names the tools only where the client hasff mcpregistered.ff resolveopens a session branch the wayff editdoes, with the hold staying on the branch you left;ff donelands the fixes and returns in one operation, andff statuscarries the session underresolvingon both branches.- The manifest's
skillsfield names skills, andff hookasksff-<name> --ff-skill <skill>for each one's files, installed whole beside fufu's own; a failed handshake isextension/skill-failedorextension/bad-skill. A registry record from before reads as unreadable untilff extension add <name>rewrites it.undoableandverbs[].read_onlyare informational. ff update -yis one answer for the whole walk: a channel it cannot drive is named at the end and the exit is 1 there, after every extension has been reached.- "Working copy" replaces "working tree" everywhere fufu speaks.
- Changes made outside fufu render as one summary line in the reconcile preamble and the block
ff statuspins;ff status --jsonstill carries every ref. - A
git rebasetyped through the shell alias is coached towardff restackunderfufu.gitPolicy=coachand refused understrict.
Removed¶
fufu.toolPolicy, with the presence markerff mcpheld for it and theff trigger clauderefusal it drove.usage/mcp-verb-unavailable,usage/mcp-extension-undeclared,usage/mcp-extension-not-undoable, andusage/mcp-policy-write, with the sealed keys under the tool.ff co, the hidden alias on thecheckoutforeign verb.
Fixed¶
ff switch,ff done, and the resolution landing recorded an end tree without the untracked files of the park they resumed, so the nextff undodeleted the files instead of stepping back.ff switchaway during a resolution no longer overwrites the branch's parked change with the marker tree.ff pull,ff restack,ff absorb, and every other replay walked a range by commit date as well as ancestry, so a commit dated older than the base was left out of the replay, and a branch made only of such commits was refused as already sitting on its base. In a shallow clone the walk stops at the boundary.ff extension removebeforeff hook claudeno longer leaves the extension's skills in the plugin. The Codex half of the v0.12.0 known issue stands.
v0.12.1 — 2026-09-04¶
Fixed¶
- Bare
ffcounts a parked change's untracked files, so the map's(+ parked change, N)and the numberff switchprints on arrival agree. - The agent skill described
ff restack,ff sync, and held rewrites as they were before the cascade, so an agent was told a conflicted replay left nothing changed and thatff synccovered one branch. - The refusal for an undeclared extension names
ff <name>as the command to run, where it showed only theff-<name>binary on PATH and left the shell exemption toff explain.
v0.12.0 — 2026-09-04¶
Added¶
- The cascade:
ff restack,ff sync,ff absorb,ff lift,ff describe <rev>, andff donereplay the branches stacked on the one they moved, inside the same operation. A branch that conflicts is held on its own;ff restackandff syncexit 3 when any did. ff synccovers the whole repository: one fetch, then every local branch is brought up to date with its shared copy and its base, parent before child.ff mcp, a Model Context Protocol server on stdio serving fufu's verbs as one tool.ff hook <client>registers it beside the capture hook.fufu.toolPolicy: what fufu says when an agent runsffin its shell while that tool is up.observe,coach, orstrict, the default.- Extensions can declare themselves.
ff extension add <name>records whatff-<name>says it is, and fufu then describes that verb to an agent everywhere it already speaks.docs/reference/extensions.mdis the reference. ff configrefuses a write tofufu.gitPolicyorfufu.toolPolicythrough thefftool, so an agent cannot lower the tier policing it.
Changed¶
ff <verb> --helpis shorter, and the pages take subheadings and lists.
Fixed¶
ff restackandff resolveon a branch whose base was rewritten replay the branch's own commits alone, bounded at the fork point rather than at the merge base with the rewritten tip.
Known issues¶
- A subscriber's injected
contextis uncapped, where fufu's own briefing line is dropped past 240 characters. - An extension's tool list is held for the life of the connection, so a client restart is what picks up an edited one. Two produced tools can collide on one name, and the later is dropped without a word.
ff doctorcompares a declared extension's recorded version, so an edit without a version bump drifts unreported. A changedmcp.argsis reported stale and not repaired by--fix.ff extension removebeforeff unhookleaves that extension's skills directory and its Cursor and Gemini registrations behind.
v0.11.0 — 2026-09-02¶
Added¶
- The error id index,
docs/reference/errors.md: every idff explainknows, with its exit code and one-line meaning, generated from the registry.ff explain --jsonentries carryexit, the code the id exits with, andff explain --listprints it as a column. prepare-commit-msgandpost-commit, the two commit-time hooks fufu did not implement.ff commitnow runs all four:pre-commit,prepare-commit-msg,commit-msg,post-commit. Every commit hook runs withGIT_EDITOR=:, as git sets it for a command that will not open an editor.--no-verifyonff absorb,ff done, andff describe <rev>, the verbs that can now be declined by a hook.ff hook powershell.$PROFILEgetsfunction git { ff git @args }and a wrappedprompt, with the same marker and the sameff unhookas the other shells. On Windows the profile is PowerShell 7's under the Documents known folder, or Windows PowerShell 5.1's when that is the only one on disk, and the slug is always detected; elsewhere it is~/.config/powershell/, detected when the profile exists or$SHELLispwsh.
Changed¶
ref/contendedexits 4 instead of 1, the one code that means nothing was touched and the same command run again is the answer. 3 keeps meaning a human is needed.ff updatenames the command that updates this copy of fufu instead of downloading a binary over itself:cargo installfor a source build,brew upgrade fufufor Homebrew, the install script for a binary at the install script's own path, and the releases page for anything else. It runs that command only on-yor a typed yes, and-yon a channel it cannot drive exits 1. The only binary fufu will ever replace is the one at the install script's own path, and the install script is what replaces it.- The background update check still runs on
fufu.updateCheckand still lands a one-line notice, but nothing installs itself any more. The notice names whichever command owns the binary. install.shandinstall.ps1land the new binary beside the old one and rename, rather than writing over it, so they can replace anffthat is currently running.
Removed¶
fufu.autoUpdate. Silent background installs are gone; there is nothing left for the setting to turn off.- The in-process downloader — asset selection, sha256 verification, archive extraction, and the binary swap — along with the four dependencies it needed:
sha2,tar,flate2, and the windows-onlyzip.
Fixed¶
- A CRLF rc file keeps its line endings through
ff unhookand through the retired-spelling rewriteff hookdoes; both rejoined the file with LF. ff absorb,ff done, andff describe <rev>ran no hooks at all, so content apre-commitgate would decline on a close landed in the commit anyway.pre-commitnow runs forff absorband for both offf done's landings — the edit session and the resolution — over the index staged with exactly what is landing, and the message hooks run forff describe <rev>and for anff donewhose session carries a new description.ff lift,ff restackandff syncstill run none, matchinggit rebase.ff syncfailed its whole run when a linked worktree's admin dir under.git/worktrees/held agitdirfile without a readablecommondir— the state such a directory passes through while it is being created or removed. git ignores such a directory; fufu's native fetch stopped on it. The fetch is now retried once throughgit fetch, which walks past it, and the error names the offending admin dir when that fails too.- A held rewrite whose later commit merged its own change into a standing conflict marker left
ff doneunable to land any resolution: the blockff resolveshowed was no longer the block the step that owned it had written, and every fix was refused withno marker block to resolve at <path>. The chain now stops at that fold, the same way it stops when two conflicts interleave, soff resolveshows the mark as its owning commit wrote it andff donelands the fix.
v0.10.0 — 2026-09-01¶
Added¶
- Documentation site at https://tyler-johnson.github.io/fufu/: tutorial, concepts, task guides, CLI reference, and a section on running fufu behind an agent.
- Commit signing, using git's own configuration (
commit.gpgsign,gpg.format,user.signingkey, and the program keys) in all three formats git supports: openpgp, x509, and ssh. Rewrites sign as well.ff commitaccepts-Sand--no-sign. ff logandff statusmark signed commits;ff log --signaturesverifies them and reports the verdict, tool, and key;ff showverifies the commit it prints;ff doctorreports whether the signing setup will work.fufu.gitPolicy, with levelsobserve,coach(default), andstrict, covering bothff gitand a baregitrun inside an agent's shell tool.ff doctorreports the tally.
Changed¶
ff --helpgroups its commands under the same headingsgit helpuses, instead of one alphabetical list.ff -hshows a short list of common verbs.- The CLI reference and the config key list are generated from the binary's help pages and checked byte for byte in CI.
- Subagents, and repositories an agent has just entered, now receive the agent briefing. Claude Code's plugin installs
StopandSubagentStopcapture events.
Removed¶
fufu.translate, replaced byfufu.gitPolicy. Command translation is gone entirely: fufu will not run a different command than the one given.
Fixed¶
ff trimreported a live branch as gone when its operations had aged out of the keep window.- With multiple worktrees, reconcile reported branch deletions and creations that had not happened, when another worktree held the branch.
Known issues¶
- With signing enabled,
ff statusno longer predicts the next commit's sha.
v0.9.0 — 2026-08-27¶
Hooks become one family. ff hook, ff unhook, and ff trigger serve all four integration clients (agent, shell, editor, git) from a single core, and the index is populated before hooks run, matching git's own order. fufu now ships an agent skill: ff hook --skill installs it, and the agent briefing routes to the skill instead of carrying the manual inline. ff collide now answers one pair of branches per invocation, and two lints that arrived with Rust 1.98 are resolved.
v0.8.0 — 2026-08-25¶
Linked worktrees, done properly.
- Each worktree gets its own operation chain, records only the refs it owns, and a branch can be open in only one worktree at a time; a second worktree's first command is no longer treated as a first run.
ff worktree add,ff worktree remove, andff worktree list— making and taking a worktree are operations,ff undoreverses a worktree removal by capturing before it deletes, and the list shows the chains of worktrees that are gone.- Retention and the survey reach every chain, including the ones nobody stands in, so a dead bay's work stays reachable.
ff watchsubscribes to the operation log, andff watch --allstreams every worktree in the repository on one tick.ff collidereports which branches would hit each other, backed by a new sideways-comparison axis in the core.ff -C <dir>runs fufu against another directory, andff <name>reaches for anff-<name>extension on PATH.ff restackmoves only the branch you named, the pager scrolls again (the X left LESS), and worktree paths get one spelling across platforms including Windows.
v0.7.0 — 2026-08-23¶
Remotes stop being invisible. ff publish --to names the remote and records it, ff sync's fetch speaks the git protocol itself, and ff doctor and ff status now see the remote's state. ff restack --onto accepts a base that lives on a remote, ff start gains a park line and can fork from remote branches, a branch rename carries its upstream, and branch lookups stop guessing that the remote is origin. ff -v routes through the version verb, the README's console blocks are generated from real output, and CI shards the process-spawning test legs.
v0.6.0 — 2026-08-21¶
The reading verbs and the remote verbs take shape.
ff diffshows the open change as a patch,ff showrenders one revision with header and patch,-pjoins the three views that list files, and the tree diff reads down to the line.ff commit <paths>lands a slice of the open change and leaves the rest open;ff log <paths>filters the log by path.- Sync and publish get one verb each:
ff synctakes in,ff publishsends, publish remembers the push so sync stops reversing your undo,--dry-runpreviews, and each status count names the verb that clears it. ff initandff clonemake the starting point fufu's own;ff versionreplaces the uppercase flag.ff historyshows the moves rather than the operations,ff op logshows every operation and takes a revset as its argument, and the op read verbs capture first so@means now.- Git translation becomes opt-in via the translate setting, and merge, blame, and tag join the git words fufu answers.
- The map keeps the commits that relate branches, coded failures always point at a next step, the agent notice teaches fufu and the CLI holds agents to it, and CI runs green on all three platforms with a bench gate that stops coin-flipping.
v0.5.0 — 2026-08-19¶
History rewriting lands as a verb family. A rewrite substrate arrives behind ff describe <rev>; ff absorb and ff lift are the short reach, ff restack on any branch is the primitive, and ff edit sessions are the long reach. Conflicts run on your schedule: rewrites that conflict are held for ff resolve instead of stopping you mid-flight. ff sync reports divergence on both axes and attributes it to the right side via the rewrite map, a branch's base and remote become one axis per ref, and ff status names the capture its parent row was cut from.
v0.4.0 — 2026-08-17¶
Bare ff becomes the map: the repository's branches drawn as a skeleton, every branch name bolded, and the listing speaks the tool's dialect with color. Underneath, a branch now answers to a base and a remote, and futures arrive: ff status reports what syncing would cost — clean, conflict, or fast-forward — via a commit-by-commit replay probe, before you spend the operation. Short spellings land, and git-flavored words are answered with fufu's equivalent instead of parsed.
v0.3.0 — 2026-08-16¶
The internal model consolidates and the machine surface lands.
- One log: the separate snapshot chain is retired, an operation is a log entry, and a snapshot is what an operation carries; the op log takes its own lock and stops growing with the commit log.
- Revsets: one set language and one grammar for both address spaces, git's
~/^suffixes walk the log, operations evaluate the language too, and a hex-shaped restore target is an id, never a duration. - The
ff opfamily arrives andff undosteps by runs; naming a branch isff describe -b. - Sessions become named spans of the capture chain — list them, diff them, group the log by them.
- The machine surface: every
--jsonoutput carries a versioned envelope, errors carry stable ids and exit codes carry the verdict, andff explaindocuments them;ff statuscomputes one model that both renderings read.
v0.2.0 — 2026-08-14¶
The first wave of daily-driver verbs and the presentation layer.
- New verbs:
ff startbegins new work on a fresh branch,ff helpgets a written page for every verb,ff doctorverifies the net,ff updateself-updates on two lanes,ff configspeaks fufu.* git config with a typed registry, and auto-trim enforces retention on its own. - Change-centric
ff log: an@open-change row over●commit rows with segment tips, plusff evologfor the snapshot chain itself. - jj-style reverse-hex snapshot ids with unique-prefix highlighting, a colored spine, and pager and color infrastructure gated on the TTY.
- A snapshot id index makes prefix resolution and the log family cost only the rows on screen, and
ff loghops segments instead of walking the chain. - A bench suite that measures slopes rather than milliseconds, with fixtures keyed to the binary that built them;
ff --versionnames the build it came from; a cargo-deny gate enforces permissive-only dependency licenses. ff statusshows one file list, one themed palette is chosen byfufu.theme, and usage lines sayffon Windows.
v0.1.0 — 2026-08-13¶
The founding release, in three phases on top of the DESIGN.md founding document.
- Phase 0, bedrock: a native read core on gitoxide, read-only
ff statusandff logwith human and--jsonoutput, a permanent differential test harness against the real git binary, and a zero-spawn latency proof. - Phase 1, capture: bare
ffsnapshots the working tree, plus the timeline,ff restore,ff trim, git passthrough, and agent hooks. - Phase 2, time: an operation journal with whole-repo
ff undo, tree memory, andff commit,ff switch,ff new,ff branch,ff describe. - Integrations unify under
ff hook <agent|shell|editor>, and release scaffolding lands: LICENSE, README, installers, CI and release workflows, and Windows portability gates.