koh

@june

Koh is version control for the solo developer.

V

v3.8.7 · 297 saves · 13,847 lines · updated 3 days ago

94 files
e45cc89462f8
back to HEAD
shell/6.5 KB · 2 weeks ago
src/488.4 KB · 1 week ago
apply/6.7 KB · 2 weeks ago
build/27.2 KB · 2 weeks ago
cli/117.3 KB · 1 week ago
args_test.v445 B · 2 weeks agoargs.vCommand line parsing.2.6 KB · 2 weeks agocli.vCommand line entry: dispatch table, usage text and exit codes.2.9 KB · 2 weeks agocmd_back_test.v3.2 KB · 2 weeks agocmd_back.vGoing back: koh undo, koh revert and koh load.9.7 KB · 2 weeks agocmd_build.vkoh build — build with koh.build, and upload nothing.2.6 KB · 2 weeks agocmd_diff.vkoh diff — unified diff of the working tree against a save, of one save against another, or across a session.3.3 KB · 2 weeks agocmd_doctor_test.v752 B · 2 weeks agocmd_doctor.vkoh doctor — integrity check and cleanup.3.6 KB · 2 weeks agocmd_flag.vkoh flag — mark a save unsafe, clear the mark, or list what is marked.2.4 KB · 2 weeks agocmd_init.vkoh init — write the .koh file and a default ignore list.964 B · 2 weeks agocmd_man.vkoh man — the manual, built into the binary.3.4 KB · 2 weeks agocmd_migrate.vkoh migrate — one-time conversion from Koh 2.4.3 KB · 2 weeks agocmd_offer.vkoh offer — send the local saves to this machine's remote, and, with --builds, publish a release built from them.6.9 KB · 2 weeks agocmd_peek.vkoh peek — put a save's tree in a temporary folder and print where.1.7 KB · 2 weeks agocmd_pluck.vkoh pluck — put one save's change onto the current tree.5.1 KB · 2 weeks agocmd_remote.vkoh remote — the machine's remote, set up once and used by every repo.12.2 KB · 2 weeks agocmd_save.vkoh save and koh checkpoint.2.9 KB · 2 weeks agocmd_status.vkoh status — where things stand: the save you are on, and what the working tree has that it does not.4.3 KB · 2 weeks agocmd_steal_test.v386 B · 2 weeks agocmd_steal.vkoh steal — bring another machine's saves in.18.3 KB · 1 week agocmd_strip.vkoh strip — remove a path from history, permanently.5.0 KB · 2 weeks agocmd_update.vkoh update — put a newer published koh in place of this one (§12).2.8 KB · 2 weeks agocmd_view.vkoh view — the history, browsed or printed.7.1 KB · 2 weeks agohandover.vThe cut-over hand-off.2.9 KB · 2 weeks agooutput.vOutput for the command line: the ✦ / ✗ habit, and the --json shapes agents read.1.6 KB · 2 weeks agoprogress_test.v673 B · 1 week agoprogress.vThe line a long action draws while it works (§4, "never leave the person wondering"): one line on stderr, redrawn in place and cleared when the step ends, and only when stderr is a terminal, so pipes, logs and --json never see it.3.2 KB · 1 week agoprompt.vThe strict confirm prompt, carried over from Koh 2 unchanged.1.0 KB · 2 weeks agorepo.vOpening the repo a command acts on, and the tree lookups commands share.949 B · 2 weeks ago
events/8.2 KB · 2 weeks ago
exchange/98.4 KB · 1 week ago
fmt/3.5 KB · 2 weeks ago
history/25.7 KB · 2 weeks ago
machine/8.2 KB · 2 weeks ago
migrate/30.7 KB · 2 weeks ago
release/13.6 KB · 2 weeks ago
remote/36.1 KB · 2 weeks ago
snapshot/38.2 KB · 2 weeks ago
storage/22.9 KB · 2 weeks ago
update/10.5 KB · 2 weeks ago
view/40.9 KB · 2 weeks ago
koh3.vProgram entry: hands the command line to the CLI and exits with its code.155 B · 2 weeks ago
tests/73.9 KB · 2 weeks ago
vendor/9.4 MB · 2 weeks ago
README.mdVersion control designed for the solo developer.3.7 KB · 2 weeks agov.mod122 B · 1 week agoVERSION6 B · 1 week ago
a4912c1ff71eprepare complete release notes since Koh 3.4.61 week ago9b646ddae3afdrop Intel macOS from GC-enabled Koh release targets (3.7.3)1 week ago32159c5a3fbfretain garbage collection in native release builds (3.7.2)1 week ago8649861afa07add GC decision, stray S3 data and untested commands to continuity follow-ups1 week agoa14c73a72b4drecord GC vs no-GC command-surface measurements and the stray S3 offer1 week ago1c1f11a965demake build.sh run on macOS and Linux: default to the host target, run from any directory, pin -gc none for Linux releases (3.7.1)1 week ago3b70c9b38348record verified Koh 3.7.0 installation and completed safety queue1 week ago4763d42de261default destructive changes to No and require explicit consent (3.7.0)1 week agofd90e3699437queue destructive-default audit and record legacy global-rule install conflict1 week ago4885b2554863confirm and strip multiple paths in one local transaction (3.6.0)1 week ago9b03deeeb756add confirmed batch ignore and machine-wide rules (3.5.0)1 week agof65a96914d11record that a filename platforms share is linked as <repo>-<platform> in §22.1 and §301 week ago5c3cec664646record Kepr's optional Umami tracking code in §3, §24, §25 and §301 week agoc8bb129066d4record the completed Koh 3.4.6 release and workspace verification1 week ago0e6d154ade97record installation of the verified Koh 3.4.6 release1 week agode6611b1cfa1record Koh 3.4.6 publication and verified terminal upgrades1 week ago1651d2456b48require trusted HTTPS for Koh 3 releases and remote traffic (3.4.6)1 week ago6123d2cfa911wip: prepare Koh 3.4.4 migration gate and release targets; release stripping fails, regenerate Linux artifacts1 week ago4dc9a406ab30specify release download links that end in the stored filename1 week agoa7de1cdfd691record the nina migrate fix and that koh2 is off PATH1 week agocbbdbce056743.4.3: migrate verifies a save's files by path, so a Koh 2 manifest listing them out of order no longer fails1 week ago1b380cba71f7record the streaming steal, Kepr's shared-cursor bug and the queued nina migrate failure1 week ago6365c974768aAGENTS.md: the installed binary is koh only; koh3 is gone1 week ago08121a6cbfec3.4.2: a steal over HTTPS reads the bundle as it arrives instead of holding it: peach-browser 2.5 GB -> 1.19 GB1 week agoa5a87a73a786record the bundle steal outcome, the V threading finding and the open items in CONTINUITY1 week ago17b5a2a8f9393.4.1: a steal refuses a bundle that does not end in 'end 0', so a dropped connection cannot pass for a whole repo1 week agoc01f0cf148563.4.0: a whole-repo steal reads Kepr's /koh/bundle in one request, showing MiB received, and falls back to key by key1 week ago2a137c79e5edspec: Kepr serves a public repo in one /koh/bundle response for whole-repo steals1 week agoe3e64ed0c91c3.3.1: the read-only steal note says how to offer from the copy instead of 'make it yours'1 week agoe45cc89462f83.3.0: a whole-repo steal's progress line counts files, saves and events against their totals1 week ago44adaadc6a8epoint §21.4's version at §11.1's version sources1 week ago6b75949d224erecord in §21.4, §26 and §30 that Kepr shows a repo's declared version without a build1 week agofdd23d3ee545record in §24 and §30 one tab per repo in Kepr's console, each repo's workspace on one page1 week agoeed5cdd20f5crecord in §30 Kepr's lighter front end: fetched timeline, cookie-built navbar, self-hosted fonts, immutable assets and hover prefetch1 week ago7e96519cb0berecord in §30 that Kepr works out the Atlas's data as saves land, superseding its in-memory Atlas1 week ago77f39f852d9frecord in §26 and §30 that Kepr's sync runs on its own thread, and its budget1 week ago08ca21a91b0arecord in §24, §26 and §30 that no Kepr page waits on the bucket and the bucket area's new budget1 week ago90f94a46bc19record in §24 and §30 that Kepr applies hidden paths in place and hands the list to Koh from its sync1 week agobba30a5a6637follow Kepr's .kepr/renamed marker when the remembered repo name has no head, remembering the new name (v3.2.27)1 week ago1d8f88f99d15record loading the Atlas picker on demand and shorter timeline tooltips in §301 week ago5dc71ab4eb28specify fetching Atlas panels on demand from /<repo>/atlas/panel1 week ago5fbf4e34075arecord in §30 that Kepr accepts migrated six-character save IDs1 week ago09a580e89d38note in §30 that a save larger than a batch has its objects stored ahead1 week agoefc04c210036record Kepr's names ignored in every repo in §301 week ago07644b31b3f3record that Kepr's sync lands long histories in batches in §301 week ago8f8891090423lowercase a repo's name at first offer so a folder's case never changes its Kepr URL (v3.2.26)1 week agof5cf9f314308specify the phone navbar's menu button1 week agoe52f5fdad820specify one-file build deletion, download analytics, the storage view, reporter blocking, bulk issue actions and workspace tabs1 week agoa1bce807dcd3specify Kepr's first-run setup, Account section, backup bucket and two-way bucket source1 week agoea9d92012295raise Kepr's ceiling to 12,600 and record the no-config-file, backup-bucket and deletion decisions1 week ago

← newerolder →

details

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.