README.md
Koh
Koh is version control for a solo developer working across a few machines.
Save your project, see what changed, and bring back earlier work when you need
it. Each repository keeps its history in one SQLite file, .koh, with one line
of saves. Koh is written in V.
Install
Koh runs on Apple silicon macOS and Linux on ARM64 or x86_64. New releases do not support Intel macOS or Windows.
curl -fsSL https://koh.asha.software/install.sh | sh
The installer verifies the release checksum and offers an optional zsh plugin.
For later updates, run koh update. Use koh update --check to check without
installing.
Start saving
Run these commands in your project folder:
koh init
koh save "record the first working version"
koh status
koh view
init creates .koh and a starter .kohignore. Check the ignore rules before
your first save. Each save snapshots every file Koh tracks, including new
files; unchanged contents are stored only once. save refuses when nothing
changed.
Before a change you may want to undo, make a checkpoint:
koh checkpoint "before changing the parser"
A checkpoint records the project even when nothing changed. After editing,
koh diff shows the changes and koh save "describe the result" records them.
Commands work from subfolders too.
koh view opens an interactive history browser in a terminal. Use the arrow
keys or j and k to move, / to search, Enter for details, and Tab to switch
between saves and checkpoints. With --json or when piped, it prints history.
LOG.md is a generated summary of the latest 20 saves.
Bring back earlier work
| Command | What it does |
|---|---|
koh undo |
Restore the previous save. |
koh undo 3 |
Step back three saves. |
koh load <id> |
Restore a particular save. |
koh load --checkpoint |
Restore the latest checkpoint. |
koh revert |
Discard unsaved changes, keeping them in a checkpoint first. |
koh peek <id> |
Unpack a save into a temporary folder for inspection. |
koh pluck <id> |
Apply one save's changes to the current tree as a new save. |
Restoring earlier work adds a new save. The saves you stepped away from remain available, so you can load them again. Koh has no branches or lanes.
undo, load, and pluck require a clean working tree. Commands that rewrite
your files show a preview and ask for confirmation. Enter cancels; only y or
Y approves. Scripts must supply --yes to approve the action.
Sync your machines
Choose an S3 bucket or a folder remote once per machine. Every repository on that machine uses the same remote.
For a folder, such as one on a removable drive:
koh remote folder /Volumes/usb/koh
For S3, supply the endpoint, bucket, and region. Koh asks for the access keys and tests the connection before keeping the settings:
koh remote s3 https://s3.fr-par.scw.cloud my-bucket fr-par
If you run a Kepr, koh remote <kepr-host> opens its sign-in
page and lets you connect with the code it supplies. koh remote shows the
current setting. Replacing or forgetting an existing remote requires consent.
Once configured, saves and checkpoints offer their history automatically.
A failed transfer leaves the local save intact; run koh offer to retry.
On another machine, fetch a repository from outside an existing repo:
koh steal my-project
cd my-project
Inside it, koh steal brings in new history. If both machines changed a file,
Koh shows both versions and asks which one to keep. It resolves clashes per
file, without blending lines. The original saves remain available, and the
result names the save you can load to return to your previous state.
Incoming changes require confirmation. For scripts, --mine or --theirs
chooses a side for every clash; --yes separately approves applying the changes.
You can also fetch a public repository with koh steal <kepr-host>/<repo>.
That copy syncs from its public source and cannot offer back until you sign in
to that Kepr as its operator.
Ignore files and remove saved content
.kohignore holds rules for the repository and travels with its saves.
~/.kohignore adds rules for every repository on this machine and stays local.
Koh also excludes its own history files, LOG.md, and symlinks.
koh ignore cache/ output/ notes.txt
koh ignore --global scratch.txt
ignore previews the exact rules and asks once for the batch. A path already
matched in the selected ignore file proposes removing its matching rules;
removing a broad rule can affect other files, which the preview explains.
Local paths are relative to the current directory. Global names and paths
match at any depth in every repository.
Ignoring a file leaves its earlier saved versions in history.
koh strip <path> permanently removes a file or folder from all saves and
bans that path from future saves. It propagates the removal to the remote and other machines
as they sync. The working file stays on disk. --save <id> limits removal to
one save and does not ban the path.
Strip is the exception to Koh's growing history: it cannot be undone. It
requires a terminal and each affected path typed exactly. --yes skips only
the yes/no question. See koh man strip before using it.
Work with coding agents
Saves can record the agent's model and a session name:
koh save --agent gpt-6 --session "fix parser errors" "reject incomplete input"
koh view --session "fix parser errors" --json
koh diff --session "fix parser errors"
koh undo --session restores the state before the current session. Use the
actual model identifier and keep one session name for related work.
Commands that print data support --json. Koh refuses when a required prompt
cannot be answered, so unattended commands never wait for input. Exit codes
are 0 for success, 1 for refusal or failure, and 2 for bad usage.
Build projects and publish releases
A project's koh.build file names its build command, output, and platforms.
koh build runs it for the current machine without uploading or installing
anything. The toolchain must already be on PATH.
koh offer --builds builds every configured platform and publishes the
artifacts as a release. It requires a saved tree and a version in the project's
own files, such as VERSION, v.mod, or package.json. Ordinary saves never
publish builds. See the specification for the
file format, and koh man build or koh man offer for command options.
Back up a repository
koh doctor
koh doctor --backup /path/to/new-backup.koh
doctor checks the database, stored content, history, events, working files
and configuration. It also verifies remote history and release files by default.
Use --fast for a local check. The report names each check, its result,
and any part it could not verify. A failed check says how to fix it, and
Doctor offers to repair what it can without losing anything: on a terminal it
asks first, and --yes runs every repair.
Its backup command writes a consistent copy of .koh. Use it instead of
copying the database while Koh is using it. Keep a live .koh out of cloud
folder sync services; use offer and steal between machines.
Koh does not encrypt history. Anyone who can read the database or remote can read its saved files. Koh is intended for code and text; individual files over 512 MiB are refused.
Upgrade from Koh 2
Save unfinished work with Koh 2 first. Run koh update in a terminal and
confirm the upgrade, then run koh migrate in each repository.
Migration keeps save IDs and archives the old repository in .koh-v2/. It
imports the dev ancestry by default, falling back to main if dev has no
saves; --lane main selects the other line. Koh 3 refuses repository commands
in an unmigrated Koh 2 repository. See koh man migrate for missing file
recovery and other options.
Build from source
Use the pinned compiler, V 0.5.2 b9a2d87. A different V revision can break
Koh, and the tests reject it.
To compile V, install a C compiler and extract the
V source archive.
Copy v.c from the vc bootstrap archive
into the extracted V directory, then run these commands there. The vc revision
is pinned too because newer bootstraps can be incompatible with this V source.
mkdir -p .git
printf '%s\n' b9a2d87bc6c317739113db1d96ca89a05f8903f4 > .git/HEAD
cc -O2 -w -o v1 v.c -lm -lpthread
./v1 -o v2 cmd/v
./v2 -o v cmd/v
./v self
./v version
The .git/HEAD file lets V report the pinned revision when built from an
archive. Add the directory containing the resulting v executable to PATH.
From Koh's repository root, compile Koh with:
mkdir -p build
v -d use_bundled_libgc -o build/koh3 src/koh.v
The flag builds the GC library from V's bundled source. SQLite 3.49.1 is
vendored and compiled into the executable. Every Koh build requires Boehm
garbage collection. Release builds use sh build.sh or
koh build on the target OS and CPU. Linux releases use the host C compiler
(cc) and static C runtime libraries. Install the toolchain's static runtime
development package if needed. Zig is not required.
Cross-compiling Koh with the pinned V disables
garbage collection, so the release script refuses it.
Manual and shell integration
Run koh man for the full manual or koh man <command> for one command. The
manual source is also available in this repository.
Source shell/koh3.plugin.zsh from ~/.zshrc for a
prompt segment and tab completion. ! marks unsaved changes; ⚑ marks a
flagged head save. The plugin's header covers custom prompts, Starship, and
Powerlevel10k.
Made by Asha Software.