koh3
Version control designed for the solo developer.
timeline
atlas99 files
.agent/
.agent/
.agent
- size
- 79.3 KB
- lines
- 1,132
- files
- 2
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 4ed280970bda 2026-09-29 21:33
- saves
- 63
docs/koh-kepr-3-master-spec.md.
CONTINUITY.md
.agent/CONTINUITY.md
- size
- 74.3 KB
- lines
- 1,089
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 4ed280970bda 2026-09-29 21:33
- saves
- 62
Spec: docs/koh-kepr-3-master-spec.md. When this file and the
document disagree, the document wins.
/Users/june/Downloads/koh-kepr-addendum-a2-login-and-public-steal.md, plus the 8e row of its "Order" table and its "Done when" column, and the "Guided steal" bullets under "For the checker".
plan-8e-guided-steal.md
.agent/plan-8e-guided-steal.md
- size
- 5.0 KB
- lines
- 43
- first save
- 2c06162b58e1 2026-09-28 03:23
- last save
- 2c06162b58e1 2026-09-28 03:23
- saves
- 1
Read all of Part 3 ("guided steal") in /Users/june/Downloads/koh-kepr-addendum-a2-login-and-public-steal.md, plus the 8e row of its "Order" table and its "Done when" column, and the "Guided steal" bullets under "For the checker". They are the specification: the screens, the wording, the colors, the keys, the flags and the behaviour without a terminal. Also read this repo's AGENTS.md, .agent/CONTINUITY.md, src/cli/cmd_steal.v, src/exchange/steal.v, src/view/ (the pager and prompt helpers), src/fmt/ (the palette), and whatever renders koh diff.
docs/
docs/
docs
- size
- 144.4 KB
- lines
- 2,232
- files
- 3
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 5fbf4e34075a 2026-10-01 19:39
- saves
- 67
koh-kepr-3-master-spec.md
docs/koh-kepr-3-master-spec.md
- size
- 103.9 KB
- lines
- 1,266
- first save
- 87658431342d 2026-09-28 14:48
- last save
- 5fbf4e34075a 2026-10-01 19:39
- saves
- 31
As of 2026-09-26 · Owner: June (Asha Software)
koh2-man.txt
docs/koh2-man.txt
- size
- 25.1 KB
- lines
- 588
- first save
- f319f052973b 2026-09-23 19:42
- last save
- f319f052973b 2026-09-23 19:42
- saves
- 1
koh3-man.txt
docs/koh3-man.txt
- size
- 15.4 KB
- lines
- 378
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 8da913d7e452 2026-09-28 20:12
- saves
- 37
shell/
shell/
shell
- size
- 6.5 KB
- lines
- 172
- files
- 1
- first save
- e6ac76b8f99a 2026-09-26 02:43
- last save
- 8da913d7e452 2026-09-28 20:12
- saves
- 4
koh3.plugin.zsh
shell/koh3.plugin.zsh
- size
- 6.5 KB
- lines
- 172
- first save
- e6ac76b8f99a 2026-09-26 02:43
- last save
- 8da913d7e452 2026-09-28 20:12
- saves
- 4
koh3.plugin.zsh — Koh 3 in your zsh prompt, plus tab completion.
kiln · v2.1.0 · 6 saves · 4.2 MB ! →
The segment reads koh status --json, never the .koh file itself, so it
works with any schema and needs no sqlite3. ! means unsaved changes and
⚑ a flagged head save. Koh 2 repos (a .koh folder) are left to Koh 2's
plugin.
Install: source this file from ~/.zshrc. To keep your own prompt, set KOH_DEFAULT_PROMPT=false first and put $(koh_prompt) where you want it. koh_prompt_info gives the same text without colour, for Starship or p10k:
[custom.koh] command = "koh_prompt_info" when = "test -f .koh" shell = ["zsh"]
src/
src/
src
- size
- 484.6 KB
- lines
- 16,255
- files
- 81
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 143
apply/
apply/
src/apply
- size
- 6.7 KB
- lines
- 268
- files
- 2
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- a15db60fd5c1 2026-09-23 20:18
- saves
- 2
- used by
- cmd_pluck.v · steal.v
apply_test.v
src/apply/apply_test.v
- size
- 3.2 KB
- lines
- 127
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- a15db60fd5c1 2026-09-23 20:18
- saves
- 2
- imports
- snapshot/
pluck and by combine's replay.
apply.v
src/apply/apply.v
- size
- 3.5 KB
- lines
- 141
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- a15db60fd5c1 2026-09-23 20:18
- saves
- 2
The per-file three-way engine, shared by pluck and by combine's replay.
One save's change is applied onto the current tree file by file. For each path in scope the current content must match either the base (clean apply, take the new content) or the target (already applied, leave it); anything else refuses rather than guessing. There is no line-level merging: the unit of resolution is the file, which is why a clash is always a hard conflict.
- exports
- Plan · conflicts · three_way · in_scope
- imports
- snapshot/
build/
build/
src/build
- size
- 27.2 KB
- lines
- 846
- files
- 3
- first save
- ba2f1a3bcb27 2026-09-27 10:13
- last save
- b760c74f453b 2026-09-27 10:37
- saves
- 5
- used by
- cmd_build.v · cmd_offer.v · cmd_update.v · migrate.v · release.v · release_test.v
koh.build says, the environment a build gets, and one real build.
build_test.v
src/build/build_test.v
- size
- 10.9 KB
- lines
- 326
- first save
- ba2f1a3bcb27 2026-09-27 10:13
- last save
- b760c74f453b 2026-09-27 10:37
- saves
- 4
Unit tests for the build module: the version a project declares, what
koh.build says, the environment a build gets, and one real build.
koh.build, the platform list, the build environment, and running a build.
build.v
src/build/build.v
- size
- 10.9 KB
- lines
- 367
- first save
- ba2f1a3bcb27 2026-09-27 10:13
- last save
- 1278e421b5fc 2026-09-27 10:30
- saves
- 4
koh.build, the platform list, the build environment, and running a build.
A release is a set of built files tied to a save, and this module is the
"make the files" half: koh build runs it and stops, and
koh offer --builds runs it and publishes what came out, so both refuse the
same things for the same reasons.
- exports
- config_name · platforms · Lang · Config · read_config · this_machine · env_for · output_path · Built · build_one
version.v
src/build/version.v
- size
- 5.3 KB
- lines
- 153
- first save
- ba2f1a3bcb27 2026-09-27 10:13
- last save
- 818acd921e18 2026-09-27 10:19
- saves
- 2
The version a project declares, read from its own files.
The first source that answers wins, so a VERSION file overrides everything
and a project that already declares its version in v.mod, package.json,
Cargo.toml, Info.plist or Gradle needs no second copy to keep in step.
Nothing is evaluated: a value built from a variable or a function call is
skipped and the next source is tried, so Koh never runs a build system to
ask what version something is.
- exports
- project_version
cli/
cli/
src/cli
- size
- 115.8 KB
- lines
- 3,907
- files
- 29
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 74b41b2f570f 2026-09-29 19:43
- saves
- 84
- used by
- koh3.v
args_test.v
src/cli/args_test.v
- size
- 445 B
- lines
- 16
- first save
- bae6f36f4351 2026-09-29 13:27
- last save
- bae6f36f4351 2026-09-29 13:27
- saves
- 1
args.v
src/cli/args.v
- size
- 2.6 KB
- lines
- 104
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- bae6f36f4351 2026-09-29 13:27
- saves
- 4
Command line parsing.
Each command declares the options it takes, so a typo is refused with a usage error instead of being ignored — an agent's mistake should be loud.
- exports
- Options · Args · parse · flag · value · values_of · value_or_none · json · positional_at
cli.v
src/cli/cli.v
- size
- 2.9 KB
- lines
- 125
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 301e80efe291 2026-09-28 17:22
- saves
- 18
Command line entry: dispatch table, usage text and exit codes.
Exit codes are fixed across every command: 0 success, 1 refusal or error,
2 bad usage. Each command returns its code; nothing else calls exit.
- exports
- version · usage_text · run
- imports
- fmt/
cmd_back_test.v
src/cli/cmd_back_test.v
- size
- 3.2 KB
- lines
- 104
- first save
- 4149f626ab4a 2026-09-23 21:14
- last save
- 2369295a09d8 2026-09-25 14:34
- saves
- 4
koh undo, koh revert and koh load.
cmd_back.v
src/cli/cmd_back.v
- size
- 9.7 KB
- lines
- 292
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 15
Going back: koh undo, koh revert and koh load.
Nothing here rewinds history. A going-back command restores an earlier tree
and records that as a new save whose restores field names the save it
brought back, so the move itself can be undone.
The order matters and is the same everywhere: show what will change, ask,
record the new save, then write the files. Recording before writing means a
crash mid-restore shows up in status and revert finishes it.
- exports
- cmd_undo · cmd_revert · cmd_load · apply_restore · restore_now
- imports
- fmt/ · history/ · snapshot/ · storage/
koh build — build with koh.build, and upload nothing.
cmd_build.v
src/cli/cmd_build.v
- size
- 2.6 KB
- lines
- 88
- first save
- ba2f1a3bcb27 2026-09-27 10:13
- last save
- f0d2d40f26a8 2026-09-28 18:41
- saves
- 2
koh build — build with koh.build, and upload nothing.
Publishing is koh offer --builds; this is for the person who wants the
files, or who wants to know whether the build works at all.
koh diff — unified diff of the working tree against a save, of one save against another, or across a session.
cmd_diff.v
src/cli/cmd_diff.v
- size
- 3.3 KB
- lines
- 148
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 89802377db7a 2026-09-24 20:12
- saves
- 5
koh diff — unified diff of the working tree against a save, of one save
against another, or across a session.
cmd_doctor_test.v
src/cli/cmd_doctor_test.v
- size
- 752 B
- lines
- 32
- first save
- a8e3208a9603 2026-09-28 15:05
- last save
- a8e3208a9603 2026-09-28 15:05
- saves
- 1
koh doctor — integrity check and cleanup.
cmd_doctor.v
src/cli/cmd_doctor.v
- size
- 3.6 KB
- lines
- 123
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- f0d2d40f26a8 2026-09-28 18:41
- saves
- 8
koh doctor — integrity check and cleanup.
One source of truth means there is nothing to rebuild; what is left to check is that the file is sound and that every object a save names is really there. Doctor also tidies the things that are safe to lose: the file cache and old peek folders.
koh flag — mark a save unsafe, clear the mark, or list what is marked.
cmd_flag.v
src/cli/cmd_flag.v
- size
- 2.4 KB
- lines
- 102
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 56ab9cab6ad2 2026-09-24 20:10
- saves
- 3
koh flag — mark a save unsafe, clear the mark, or list what is marked.
A flag is an event, not a column: save records are write-once, and clearing a flag is itself an event, so flagging stays undoable and syncs like everything else.
koh init — write the .koh file and a default ignore list.
cmd_init.v
src/cli/cmd_init.v
- size
- 964 B
- lines
- 42
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 56ab9cab6ad2 2026-09-24 20:10
- saves
- 2
koh init — write the .koh file and a default ignore list.
koh man — the manual, built into the binary.
cmd_man.v
src/cli/cmd_man.v
- size
- 3.4 KB
- lines
- 126
- first save
- bcdc186ee437 2026-09-23 20:19
- last save
- 8001f6686656 2026-09-26 14:04
- saves
- 4
koh man — the manual, built into the binary.
The page lives in docs/koh3-man.txt and is embedded at build time, so a
koh copied to another machine still carries its own documentation. With a
command name it prints just that command's part; otherwise the whole page,
through the built-in pager on a terminal.
koh migrate — one-time conversion from Koh 2.
cmd_migrate.v
src/cli/cmd_migrate.v
- size
- 4.3 KB
- lines
- 128
- first save
- 884f56f0f0d2 2026-09-23 20:24
- last save
- 8da913d7e452 2026-09-28 20:12
- saves
- 7
koh migrate — one-time conversion from Koh 2.
koh offer — send the local saves to this machine's remote, and, with --builds, publish a release built from them.
cmd_offer.v
src/cli/cmd_offer.v
- size
- 6.9 KB
- lines
- 202
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 14
koh offer — send the local saves to this machine's remote, and, with
--builds, publish a release built from them.
- exports
- cmd_offer · this_machine_backend · auto_offer
- imports
- build/ · exchange/ · fmt/ · history/ · machine/ · release/ · remote/ · storage/
koh peek — put a save's tree in a temporary folder and print where.
cmd_peek.v
src/cli/cmd_peek.v
- size
- 1.7 KB
- lines
- 63
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 56ab9cab6ad2 2026-09-24 20:10
- saves
- 2
koh peek — put a save's tree in a temporary folder and print where.
The working tree and history are untouched: a peek is a read of the object store into a scratch folder the user can look at, then throw away.
koh pluck — put one save's change onto the current tree.
cmd_pluck.v
src/cli/cmd_pluck.v
- size
- 5.1 KB
- lines
- 164
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 10
koh pluck — put one save's change onto the current tree.
The engine is per file, never per line: for every path in scope the current content must match either the save's parent (clean apply) or the save's own version (already applied). Anything else is a hard conflict, reported by name, and nothing is applied.
koh remote — the machine's remote, set up once and used by every repo.
cmd_remote.v
src/cli/cmd_remote.v
- size
- 12.2 KB
- lines
- 364
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 12
koh remote — the machine's remote, set up once and used by every repo.
Setup is interactive by default, because it ends with a live connection
test: a remote is only saved once it has proved it can store an object and
refuse to overwrite it. folder and s3 forms are available for a machine
being set up by a script, and an agent can read the current setting with
--json (which never prints the secret key).
koh save and koh checkpoint.
cmd_save.v
src/cli/cmd_save.v
- size
- 2.9 KB
- lines
- 105
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 12
koh save and koh checkpoint.
koh status — where things stand: the save you are on, and what the working tree has that it does not.
cmd_status.v
src/cli/cmd_status.v
- size
- 4.3 KB
- lines
- 151
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 17c48991c43c 2026-09-29 02:36
- saves
- 11
koh status — where things stand: the save you are on, and what the working tree has that it
does not.
- exports
- cmd_status · Changes · compare_with_head
- imports
- events/ · fmt/ · history/ · snapshot/ · storage/
cmd_steal_test.v
src/cli/cmd_steal_test.v
- size
- 386 B
- lines
- 11
- first save
- 7ec030db3e06 2026-09-28 05:09
- last save
- 7ec030db3e06 2026-09-28 05:09
- saves
- 1
koh steal — bring another machine's saves in.
cmd_steal.v
src/cli/cmd_steal.v
- size
- 18.2 KB
- lines
- 563
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 74b41b2f570f 2026-09-29 19:43
- saves
- 25
koh steal — bring another machine's saves in.
Inside a repo this takes the remote's new saves and combines when both
machines moved. Outside one it fetches a whole repo into a new folder.
--list shows what the remote holds.
- exports
- cmd_steal
- imports
- events/ · exchange/ · fmt/ · history/ · remote/ · snapshot/ · storage/ · view/
koh strip — remove a path from history, permanently.
cmd_strip.v
src/cli/cmd_strip.v
- size
- 5.0 KB
- lines
- 148
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 11
koh strip — remove a path from history, permanently.
This is the only command that destroys information, so it is deliberately
loud: it needs a terminal, it warns about exactly what it will destroy, and
it asks twice — once the strict y, then the path typed out in full. Every
step is safe to repeat, so an interrupted strip finishes when it is re-run.
The file itself is left on disk. A whole-history strip bans the path: it is
added to .kohignore, and no walk of the tree picks it up again.
koh update — put a newer published koh in place of this one (§12).
cmd_update.v
src/cli/cmd_update.v
- size
- 2.8 KB
- lines
- 95
- first save
- fe3253a128c9 2026-09-27 10:45
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 4
koh update — put a newer published koh in place of this one (§12).
Nothing is installed without being asked, and nothing is removed: the new binary replaces the running one by rename, which is the step that makes the change visible.
koh view — the history, browsed or printed.
cmd_view.v
src/cli/cmd_view.v
- size
- 7.1 KB
- lines
- 267
- first save
- ea43d4f3e936 2026-09-27 14:47
- last save
- 4259fb5dff46 2026-09-27 14:52
- saves
- 2
koh view — the history, browsed or printed.
On a terminal it opens the history view on the saves tab, or on the
checkpoints tab with --checkpoints; piped, filtered, or with --json it
prints the line instead, so an agent always gets something it can parse.
handover.v
src/cli/handover.v
- size
- 2.9 KB
- lines
- 88
- first save
- 884f56f0f0d2 2026-09-23 20:24
- last save
- 2213f5046815 2026-09-29 02:07
- saves
- 5
The cut-over hand-off.
While repos with an unmigrated Koh 2 .koh/ directory still exist on this
machine, koh is Koh 3 but those repos belong to Koh 2. Rather than let a
command fail confusingly, Koh 3 hands it to koh2 unchanged — same
arguments, same terminal. Agents always type koh, and every repo gets the
Koh that owns it.
migrate is the exception: it is how such a repo stops being a Koh 2 repo.
Commands about the machine rather than the repo stay Koh 3's, and a command
Koh 2 reads differently, or lacks, is refused with the way forward.
- exports
- hand_over
- imports
- fmt/
--json shapes agents read.
output.v
src/cli/output.v
- size
- 1.6 KB
- lines
- 67
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 8
Output for the command line: the ✦ / ✗ habit, and the --json shapes
agents read.
Colour comes from src.fmt, so turning it off turns it off everywhere.
Every command that prints data has a JSON form with stable field names, and
every error is {"error": "..."} on stderr. Exit codes are fixed: 0
success, 1 refusal or error, 2 bad usage.
- exports
- ok · note · warn · fail · fail_json · usage_error · refuse · emit_json
- imports
- fmt/
--json never see it.
progress.v
src/cli/progress.v
- size
- 2.5 KB
- lines
- 112
- first save
- f0d2d40f26a8 2026-09-28 18:41
- last save
- dfe5c9f72825 2026-09-28 19:42
- saves
- 2
The 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.
prompt.v
src/cli/prompt.v
- size
- 1.0 KB
- lines
- 38
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- f0d2d40f26a8 2026-09-28 18:41
- saves
- 2
The strict confirm prompt, carried over from Koh 2 unchanged.
Before anything that rewrites the working tree, Koh shows what will happen
and asks one question. Only a lowercase y confirms: Y, yes, or a
padded y all cancel. --yes skips the question; without a terminal and
without --yes the command refuses rather than hanging.
- exports
- interactive · confirm · typed_confirm
repo.v
src/cli/repo.v
- size
- 949 B
- lines
- 39
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 76be2198e257 2026-09-23 19:53
- saves
- 1
Opening the repo a command acts on, and the tree lookups commands share.
events/
events/
src/events
- size
- 8.2 KB
- lines
- 299
- files
- 2
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 7
- used by
- cmd_flag.v · cmd_status.v · cmd_steal.v · cmd_view.v · exchange.v · exchange_test.v · records.v · steal.v · strip.v · migrate.v · migrate_test.v · view.v · +1 more
events_test.v
src/events/events_test.v
- size
- 2.0 KB
- lines
- 74
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 2369295a09d8 2026-09-25 14:34
- saves
- 4
events.v
src/events/events.v
- size
- 6.2 KB
- lines
- 225
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 5
Events: what Koh learns about saves that already exist.
Save records are write-once, so a flag is not stored on the save. It is
appended as a small event that syncs alongside saves, and a save's flag
state is always derived from the newest event about it — never stored twice.
A strip event is what makes strip visible to other machines.
exchange/
exchange/
src/exchange
- size
- 96.0 KB
- lines
- 3,114
- files
- 6
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 25
- used by
- cmd_offer.v · cmd_remote.v · cmd_steal.v · cmd_strip.v · release.v
exchange_test.v
src/exchange/exchange_test.v
- size
- 48.3 KB
- lines
- 1,585
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 16
Two-machine tests: two repos and one folder remote standing in for the Mac and the PC. This is where offer, steal and combine are actually proven — the folder backend exists so these run offline.
exchange.v
src/exchange/exchange.v
- size
- 13.3 KB
- lines
- 380
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 16
Sync: offer and steal.
All the cleverness sits here, above the five-operation remote interface, so the backends stay thin and this logic is written once and tested offline.
The remote is a line of saves, the same shape as the local one. offer
sends local saves the remote lacks; steal takes remote saves and, when
both sides moved, replays the local work on top of the remote's. Divergence
is resolved per file, never per line.
- exports
- no_saves · OfferReport · remember_repo · repo_name · offer · Fetched · fetch_back_to_known · write_fetched · write_fetched_records
- imports
- events/ · history/ · remote/ · snapshot/ · storage/
records.v
src/exchange/records.v
- size
- 6.2 KB
- lines
- 236
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 6
What a save and an event look like on the remote.
Records are JSON so a person can read the bucket, and the layout is the same for every backend:
<repo>/format the remote layout, koh-remote 1
<repo>/objects/<hash> the object's compressed bytes, as in the table
<repo>/saves/<id> the full save record, including its file list
<repo>/events/<id> one flag, clear or strip event
<repo>/head the ID of the newest save on the line
Only head is ever overwritten, and only with a matching version tag.
- exports
- format_key · object_key · save_key · event_key · head_key · events_prefix · FileRecord · SaveRecord · save_record · encode_save · decode_save · drop_unsafe_paths · +6 more
- imports
- events/ · history/ · snapshot/ · storage/
source.v
src/exchange/source.v
- size
- 1.6 KB
- lines
- 45
- first save
- 2b1e04f61099 2026-09-27 16:01
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 2
A repo stolen from a Kepr that is not signed in: its own address, kept read-only.
This is the addendum's one exception to the machine-wide remote rule. The
address lives in the repo's state, so nothing about it can leak into another
repo, and it is dropped the moment this machine signs in to that Kepr.
- exports
- source_of · source_host · signed_in_to · read_only · remember_source · forget_source
- imports
- machine/ · remote/ · storage/
steal.v
src/exchange/steal.v
- size
- 19.2 KB
- lines
- 628
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 064fb290d6cf 2026-09-29 02:48
- saves
- 17
Stealing: bringing another machine's saves in, and combining when both machines moved.
The order is always the same, and it is what makes an interrupted steal harmless: read everything from the remote first, then land it in one transaction, then write the working tree. Divergence is resolved per file — a clash is never blended line by line, it is chosen.
- exports
- Side · Clash · StealPreview · StealOptions · StealReport · dirty_tree · ClashError · msg · no_saves_here · steal · find_clashes · dirty · +1 more
- imports
- apply/ · events/ · fmt/ · history/ · remote/ · snapshot/ · storage/
strip.v
src/exchange/strip.v
- size
- 7.4 KB
- lines
- 240
- first save
- 56ab9cab6ad2 2026-09-24 20:10
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 8
Strip: removing a path from history, here and on the remote.
The local half is one transaction: the saved files go, the objects nobody references go, a strip event is recorded, and so is a note of which objects the remote may now drop. The remote half reads that note, so it can be re-run after an interruption even though the local rows are long gone.
fmt/
fmt/
src/fmt
- size
- 3.5 KB
- lines
- 169
- files
- 1
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 4
- used by
- cli.v · cmd_back.v · cmd_build.v · cmd_diff.v · cmd_doctor.v · cmd_flag.v · cmd_man.v · cmd_migrate.v · cmd_offer.v · cmd_peek.v · cmd_pluck.v · cmd_remote.v · +12 more
fmt.v
src/fmt/fmt.v
- size
- 3.5 KB
- lines
- 169
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 4
Presentation primitives shared by the two places Koh prints: the command line and the full-screen history view.
Colour lives here so both surfaces use one palette, and NO_COLOR /
KOH_NO_COLOR turn it off for both at once.
- exports
- glyph_ok · glyph_fail · colour_enabled · bold · reverse · amber · red · green · dim · gold · muted · blue · +11 more
history/
history/
src/history
- size
- 25.7 KB
- lines
- 818
- files
- 4
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 15
- used by
- cmd_back.v · cmd_back_test.v · cmd_diff.v · cmd_doctor.v · cmd_doctor_test.v · cmd_flag.v · cmd_offer.v · cmd_peek.v · cmd_pluck.v · cmd_save.v · cmd_status.v · cmd_steal.v · +14 more
history_test.v
src/history/history_test.v
- size
- 9.6 KB
- lines
- 310
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 7
history.v
src/history/history.v
- size
- 6.5 KB
- lines
- 229
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 6
History: one line of saves, and the queries every command needs.
- exports
- Save · head · head_id · by_id · resolve · all_saves · line · effective · step_back · session_start · last_session · session_saves · +4 more
- imports
- snapshot/ · storage/
log_md.v
src/history/log_md.v
- size
- 1.6 KB
- lines
- 47
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 5
LOG.md: the one-screen history Koh keeps at the repo root for people (and agents) who want the last few saves without running a command.
- exports
- refresh_log_md
- imports
- storage/
save.v
src/history/save.v
- size
- 8.1 KB
- lines
- 232
- first save
- 2369295a09d8 2026-09-25 14:34
- last save
- 4fedb4de22e5 2026-09-29 02:40
- saves
- 4
Creating saves.
A save is a full snapshot: every tracked path with its object hash and
executable bit, plus the message, time, machine and optional agent and
session. Its ID is the first 12 hex characters of the Blake3 hash of the
canonical record, computed once, at creation, and never recomputed — which
is why strip can change a save's files and keep its ID.
machine/
machine/
src/machine
- size
- 8.2 KB
- lines
- 280
- files
- 3
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 6
- used by
- cmd_migrate.v · cmd_offer.v · cmd_remote.v · cmd_strip.v · events.v · source.v · save.v · release.v · release_test.v
machine.v
src/machine/machine.v
- size
- 404 B
- lines
- 18
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 76be2198e257 2026-09-23 19:53
- saves
- 1
Machine-local facts: the name recorded on saves, and where Koh keeps the settings that belong to this machine rather than to a repo.
- exports
- name · config_dir · config_path
settings_test.v
src/machine/settings_test.v
- size
- 3.0 KB
- lines
- 96
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- a63030364948 2026-09-23 22:27
- saves
- 2
settings.v
src/machine/settings.v
- size
- 4.8 KB
- lines
- 166
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 5
Machine-wide remote settings.
Everything machine-specific lives in ~/.config/koh/, never inside a repo:
one remote per machine, and the S3 keys in a file only the user can read.
The format is plain key=value lines so it can be read and edited by hand.
- exports
- remote_file · credentials_file · kind_folder · kind_s3 · RemoteSettings · Credentials · save_remote · load_remote · has_remote · forget_remote · save_credentials · load_credentials
migrate/
migrate/
src/migrate
- size
- 30.7 KB
- lines
- 995
- files
- 2
- first save
- 884f56f0f0d2 2026-09-23 20:24
- last save
- 135d14574f3d 2026-09-29 16:55
- saves
- 14
- used by
- cmd_migrate.v
migrate_test.v
src/migrate/migrate_test.v
- size
- 12.9 KB
- lines
- 390
- first save
- 884f56f0f0d2 2026-09-23 20:24
- last save
- 8da913d7e452 2026-09-28 20:12
- saves
- 13
Migration tests, run against a fixture made by the Koh 2 binary itself.
The fixture is why these are worth having: it is not a guess at Koh 2's
format, it is the format, including the inlined small files and the object
store. When koh (Koh 2) is not on the machine these tests skip rather
than pretend.
koh migrate — convert one Koh 2 repo into a Koh 3 repo, in place.
migrate.v
src/migrate/migrate.v
- size
- 17.9 KB
- lines
- 605
- first save
- 884f56f0f0d2 2026-09-23 20:24
- last save
- 135d14574f3d 2026-09-29 16:55
- saves
- 10
koh migrate — convert one Koh 2 repo into a Koh 3 repo, in place.
Koh 2 kept one JSON manifest per save plus an object store; Koh 3 keeps the
same objects in one SQLite file. The conversion reads the manifests as the
source of truth, imports everything into a fresh .koh, verifies it against
those manifests, and only then swaps it into place. The Koh 2 data is not
deleted — it is moved aside as .koh-v2/, so trash .koh and moving it back
undoes the migration entirely.
release/
release/
src/release
- size
- 13.6 KB
- lines
- 411
- files
- 2
- first save
- e042d2bfc1ff 2026-09-27 10:26
- last save
- b760c74f453b 2026-09-27 10:37
- saves
- 3
- used by
- cmd_offer.v
release_test.v
src/release/release_test.v
- size
- 7.9 KB
- lines
- 238
- first save
- e042d2bfc1ff 2026-09-27 10:26
- last save
- b760c74f453b 2026-09-27 10:37
- saves
- 2
Folder-backend tests for publishing: what lands in the bucket, what a retry does, what a second build of the same version does, and the notes rule.
release.v
src/release/release.v
- size
- 5.7 KB
- lines
- 173
- first save
- e042d2bfc1ff 2026-09-27 10:26
- last save
- b760c74f453b 2026-09-27 10:37
- saves
- 3
Releases: the built files, the record that names them, and their keys in the bucket.
A version exists the moment its release.json lands (§11.2), so history goes
up first, then every file, then the record, and releases/latest moves last.
Kepr reads all of it back field by field, so this record and ReleaseRecord
in Kepr's src/bucket/repo.ts are one contract: a name here that Kepr
refuses would fail the whole repo's sync.
remote/
remote/
src/remote
- size
- 36.1 KB
- lines
- 1,165
- files
- 8
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 18
- used by
- cmd_offer.v · cmd_remote.v · cmd_steal.v · progress.v · exchange.v · exchange_test.v · source.v · steal.v · strip.v · release.v · release_test.v
folder_test.v
src/remote/folder_test.v
- size
- 3.3 KB
- lines
- 106
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 81b27aa9028d 2026-09-26 02:48
- saves
- 4
folder.v
src/remote/folder.v
- size
- 4.3 KB
- lines
- 170
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- e787dbe6181a 2026-09-23 22:28
- saves
- 3
The folder backend: a remote that is just a directory.
Every sync test in the project runs against this backend, because it needs no network and no account. It is also a real backend in its own right — a sync folder on an external disk or a NAS is a perfectly good remote.
Publish is a hard link, which fails when the name already exists: no partial file and no overwrite is ever visible to a reader.
- exports
- Folder · new_folder · get · list · put_if_absent · put_if_match · delete · tag_of
remote.v
src/remote/remote.v
- size
- 2.1 KB
- lines
- 59
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 81b27aa9028d 2026-09-26 02:48
- saves
- 4
The remote interface: five operations, two backends.
A remote is dumb storage that can do one safe swap. Everything clever —
what to upload, what diverged, how to combine — lives in src/exchange, above
this interface, so the folder and S3 backends stay thin and the sync logic
is written once and tested offline.
- exports
- Object · Backend · probe_key · check
s3_test.v
src/remote/s3_test.v
- size
- 6.8 KB
- lines
- 184
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- cb84f9ea35c4 2026-09-24 16:09
- saves
- 3
s3.v
src/remote/s3.v
- size
- 7.7 KB
- lines
- 265
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 7
The S3 backend: plain HTTPS with SigV4 signing against any S3 endpoint.
Only the two conditional writes matter for correctness — If-None-Match: *
for objects and saves, If-Match for head — because they are what stops
two machines from silently overwriting each other. Everything else is
ordinary GET, DELETE and ListObjectsV2.
- exports
- s3_service · retry_attempts · S3 · new_s3 · get · list · put_if_absent · put_if_match · delete · elements
sigv4.v
src/remote/sigv4.v
- size
- 4.8 KB
- lines
- 152
- first save
- a15db60fd5c1 2026-09-23 20:18
- last save
- 1af9dc58a448 2026-09-23 21:40
- saves
- 2
AWS Signature Version 4, the part S3 needs.
Signing is a fixed recipe: canonicalise the request, hash it, derive a key
from the secret for that day and region, and sign the string-to-sign. It is
all here in the open, and pinned to the published AWS get-vanilla vector,
so the signer is checked rather than trusted.
- exports
- Signer · sign · amz_timestamp · UrlParts · split_url · canonical_query · encode
web_test.v
src/remote/web_test.v
- size
- 4.0 KB
- lines
- 125
- first save
- 2b1e04f61099 2026-09-27 16:01
- last save
- 2b1e04f61099 2026-09-27 16:01
- saves
- 1
The web backend: public repos over HTTP, and never a write.
web.v
src/remote/web.v
- size
- 3.1 KB
- lines
- 104
- first save
- 2b1e04f61099 2026-09-27 16:01
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 5
The web backend: read-only access to a public Koh mirror.
- exports
- Web · new_web · kepr_host · get · list · put_if_absent · put_if_match · delete
snapshot/
snapshot/
src/snapshot
- size
- 38.2 KB
- lines
- 1,297
- files
- 6
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 4fedb4de22e5 2026-09-29 02:40
- saves
- 24
- used by
- apply.v · apply_test.v · cmd_back.v · cmd_back_test.v · cmd_diff.v · cmd_doctor.v · cmd_doctor_test.v · cmd_init.v · cmd_migrate.v · cmd_peek.v · cmd_pluck.v · cmd_save.v · +18 more
diff.v
src/snapshot/diff.v
- size
- 4.8 KB
- lines
- 186
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 71d55a793226 2026-09-23 22:34
- saves
- 3
Comparing trees: which files changed, how much, and the unified diff.
Both sides of a comparison are Trees — the working tree (files on disk)
or a save (files in the object store) — so every diff Koh offers, working
tree against a save, save against save, is the same call.
The unified diff itself comes from diff(1): it is present on both target
platforms, handles the edge cases, and keeps a thousand lines of line-matching
code out of Koh. Koh only parses its output for the +/- counts.
- exports
- Tree · Delta · binary_notice · changes · diff_trees · diff_bytes · index_files
- imports
- storage/
fs.v
src/snapshot/fs.v
- size
- 1.2 KB
- lines
- 62
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 76be2198e257 2026-09-23 19:53
- saves
- 1
Filesystem facts the walk needs: kind, size, mode and nanosecond times.
V's own os.Stat reports mtime in whole seconds, which is too coarse for
the file cache — a file edited twice inside one second would keep a stale
hash and the next save would record the wrong content. vendor/shim gives
the nanosecond times and tells symlinks apart from files in one call.
- exports
- C · Kind · Stat · lstat · is_executable
ignore.v
src/snapshot/ignore.v
- size
- 6.6 KB
- lines
- 265
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 7
Ignore rules.
.kohignore lives at the repo root and is itself snapshotted, so the rules
travel between machines with the history. Patterns are matched against
repo-relative paths: * matches inside one path segment, ** spans
segments, a trailing / restricts a pattern to directories, a leading
/ anchors it to the repo root, and \ makes the next character literal.
- exports
- default_ignore · ignore_file · Ignore · load · add_ignore · parse · hard_ignored · matches
restore.v
src/snapshot/restore.v
- size
- 6.5 KB
- lines
- 181
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 4fedb4de22e5 2026-09-29 02:40
- saves
- 11
Writing a tree back onto disk.
A restore writes the target's files and deletes the tracked files the target does not have. An ignored file already on disk is never overwritten or deleted, and every file lands through a temp file and a rename, so an interrupted restore leaves a readable tree rather than half-written files.
- exports
- restore_unfinished · restore_pending · mark_restore · clear_restore_mark · RestoreReport · restore_files · check_links
- imports
- storage/
snapshot_test.v
src/snapshot/snapshot_test.v
- size
- 12.0 KB
- lines
- 373
- first save
- 525088cda79c 2026-09-23 19:54
- last save
- dfe5c9f72825 2026-09-28 19:42
- saves
- 11
- imports
- storage/
tree.v
src/snapshot/tree.v
- size
- 7.1 KB
- lines
- 230
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 4fedb4de22e5 2026-09-29 02:40
- saves
- 11
Walking the working tree: ignore rules, hashing, and the file cache.
- exports
- FileEntry · WalkReport · legal_path · escape_path · Counted · Hashing · walk · walk_report · walk_raw · store_objects · same_tree
- imports
- storage/
storage/
storage/
src/storage
- size
- 22.9 KB
- lines
- 878
- files
- 5
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 14
- used by
- cmd_back.v · cmd_back_test.v · cmd_diff.v · cmd_doctor.v · cmd_doctor_test.v · cmd_flag.v · cmd_init.v · cmd_offer.v · cmd_pluck.v · cmd_remote.v · cmd_status.v · cmd_steal.v · +25 more
status and save can skip files whose size, mtime and ctime are unchanged.
cache.v
src/storage/cache.v
- size
- 2.2 KB
- lines
- 87
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 4
The file cache: a machine-local shortcut so status and save can skip
files whose size, mtime and ctime are unchanged. It caches the working
tree, never history, and is safe to drop at any time.
- exports
- CacheRow · load_cache · save_cache_rows · drop_cache · cache_count
objects.v
src/storage/objects.v
- size
- 4.7 KB
- lines
- 169
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- bea6866dbe3e 2026-09-26 02:41
- saves
- 4
The object table: content-addressed file bytes.
Objects are Blake3-addressed and stored zlib-compressed, exactly as Koh 2 stored them on disk, so the same bytes migrate without a re-hash and a future reader can decompress them with any zlib. Objects are shared between saves: identical content is stored once.
- exports
- max_file_size · hash_hex · put_object · object_blob · put_object_blob · has_object · get_object · object_size · object_count · drop_unreferenced_objects · check_objects · check_save_files
sqlite_test.v
src/storage/sqlite_test.v
- size
- 2.5 KB
- lines
- 90
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 4d41f88e04ed 2026-09-24 04:51
- saves
- 3
vendor/sqlite.
sqlite.v
src/storage/sqlite.v
- size
- 7.2 KB
- lines
- 279
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 5
SQLite bindings over the vendored amalgamation in vendor/sqlite.
V's own db.sqlite module links whatever SQLite the host provides. Koh
links its own copy instead, so macOS and Linux run the same SQLite and the
build depends on nothing outside the repo. Only the calls Koh needs are
declared here — no ORM, no pooling, no reflection.
- exports
- C · libversion · Db · connect · close · last_error · changes · exec · Stmt · prepare · bind_text · bind_blob · +10 more
.koh file: schema, connection settings and machine-local state.
storage.v
src/storage/storage.v
- size
- 6.4 KB
- lines
- 253
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 16c0fc007c1f 2026-09-29 13:32
- saves
- 9
The .koh file: schema, connection settings and machine-local state.
One file at the repo root holds everything — objects, saves, events and bookkeeping. There is no second source of truth, so there is nothing to rebuild, verify against, or recover.
- exports
- schema_version · file_name · busy_timeout_ms · head_key · Store · find_root · open · open_at · create · create_at · close · busy · +9 more
update/
update/
src/update
- size
- 10.5 KB
- lines
- 316
- files
- 2
- first save
- fe3253a128c9 2026-09-27 10:45
- last save
- 67dcb773afe1 2026-09-28 18:27
- saves
- 5
- used by
- cmd_update.v
koh update: ordering versions, decoding a release document, and the two checks that stand between a download and the binary.
update_test.v
src/update/update_test.v
- size
- 3.6 KB
- lines
- 105
- first save
- fe3253a128c9 2026-09-27 10:45
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 3
Unit tests for koh update: ordering versions, decoding a release
document, and the two checks that stand between a download and the binary.
koh update — put a newer published koh in place of this one (§12).
update.v
src/update/update.v
- size
- 6.9 KB
- lines
- 211
- first save
- fe3253a128c9 2026-09-27 10:45
- last save
- 67dcb773afe1 2026-09-28 18:27
- saves
- 5
koh update — put a newer published koh in place of this one (§12).
The source is a release document: Kepr's /koh/releases/latest.json by
default, or whatever KOH_UPDATE_SOURCE names. Koh installs only a
newer version than the one running, never merely a different one, so a
stale mirror cannot walk the binary backwards. Nothing is ever built here.
- exports
- default_source · source_env · repo · Available · source · Checked · check · compare_versions · install
view/
view/
src/view
- size
- 40.9 KB
- lines
- 1,483
- files
- 5
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 16
- used by
- cmd_man.v · cmd_remote.v · cmd_steal.v · cmd_view.v · progress.v
runMan (src/pager.zig): a page at a time, Tab and Shift-Tab jump between sections, and the status bar names the section at the top of the page.
manual.v
src/view/manual.v
- size
- 4.1 KB
- lines
- 160
- first save
- 6554688b6256 2026-09-26 13:45
- last save
- c0fab999e938 2026-09-28 04:24
- saves
- 2
The manual's pager, Koh 2's runMan (src/pager.zig): a page at a time,
Tab and Shift-Tab jump between sections, and the status bar names the
section at the top of the page.
- exports
- ManualLine · page_manual · page_text · manual_frame · section_page
term_test.v
src/view/term_test.v
- size
- 1.5 KB
- lines
- 38
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 6554688b6256 2026-09-26 13:45
- saves
- 3
term.v
src/view/term.v
- size
- 2.9 KB
- lines
- 193
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 17c48991c43c 2026-09-29 02:36
- saves
- 4
Terminal control and key decoding for the history view.
The view owns the screen while it runs, so raw mode and the alternate screen have to be entered and left reliably, on every exit path. Rendering is a plain string of ANSI escapes written in one call per frame — no redraw diffing, because the whole frame is small and the terminal does that faster than we can.
- exports
- KeyKind · Key · terminal_size · raw_mode · read_key
- used by
- cmd_remote.v
view_test.v
src/view/view_test.v
- size
- 13.2 KB
- lines
- 369
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 10
view.v
src/view/view.v
- size
- 19.2 KB
- lines
- 723
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 1f6a60e93364 2026-09-29 02:45
- saves
- 12
The history view: the saves and checkpoints list, full screen.
On a terminal koh view opens this instead of printing; --checkpoints
opens it on the checkpoints tab. The look and the keys are Koh 2's
(src/commands/history.zig): a tab bar, evenly spaced entries between
separators, and a status bar with the hints for the current mode.
The view only reads — history, flags and diffs — and hands any decision back
to the caller as an Action, so the command layer stays the only thing that
changes anything. frame_lines turns a Session into the rows of one frame,
which keeps the interesting part testable without a terminal.
koh3.v
src/koh3.v
- size
- 155 B
- lines
- 9
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 4d519567736f 2026-09-29 02:32
- saves
- 2
Program entry: hands the command line to the CLI and exits with its code.
- imports
- cli/
tests/
tests/
tests
- size
- 73.9 KB
- lines
- 1,895
- files
- 2
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 74b41b2f570f 2026-09-29 19:43
- saves
- 70
cli_test.v
tests/cli_test.v
- size
- 69.3 KB
- lines
- 1,755
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 74b41b2f570f 2026-09-29 19:43
- saves
- 67
library_check_test.v
tests/library_check_test.v
- size
- 4.6 KB
- lines
- 140
- first save
- f319f052973b 2026-09-23 19:42
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 3
Phase 0 library checks.
Koh 3 depends on five things outside its own source: SQLite (verified in src/storage), Blake3, zlib, SHA-256/HMAC and an HTTP client. This file pins the behaviour Koh relies on for the four stdlib ones, against vectors produced by other implementations of the same algorithms. If a V upgrade breaks an assumption, it breaks here rather than in a save.
vendor/
vendor/
vendor
- size
- 9.4 MB
- lines
- 275,353
- files
- 6
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 942d08c78d27 2026-09-23 20:04
- saves
- 3
shim/
shim/
vendor/shim
- size
- 5.2 KB
- lines
- 184
- files
- 4
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 942d08c78d27 2026-09-23 20:04
- saves
- 2
koh_stat.c
vendor/shim/koh_stat.c
- size
- 939 B
- lines
- 32
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 76be2198e257 2026-09-23 19:53
- saves
- 1
- imports
- koh_stat.h
koh_stat.h
vendor/shim/koh_stat.h
- size
- 868 B
- lines
- 25
- first save
- 76be2198e257 2026-09-23 19:53
- last save
- 76be2198e257 2026-09-23 19:53
- saves
- 1
Nanosecond-precision lstat for the working-tree walk.
V's os.Stat exposes mtime and ctime in whole seconds. The file cache in
src/snapshot decides whether a file may skip hashing by comparing those
timestamps, so second precision would let a file edited twice inside one
second keep a stale hash — and a save would then record the wrong content.
This shim reports nanoseconds, plus the file kind, which the walker needs to
skip symlinks and directories without a second stat call.
- used by
- koh_stat.c
koh_term.c
vendor/shim/koh_term.c
- size
- 2.5 KB
- lines
- 102
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 942d08c78d27 2026-09-23 20:04
- saves
- 1
- imports
- koh_term.h
koh_term.h
vendor/shim/koh_term.h
- size
- 961 B
- lines
- 25
- first save
- 942d08c78d27 2026-09-23 20:04
- last save
- 942d08c78d27 2026-09-23 20:04
- saves
- 1
Terminal control for the history view.
The view needs three things V's standard library does not expose directly: raw mode with the terminal restored on exit, the window size, and one keystroke at a time with escape sequences kept together. Keeping this in C means one implementation for macOS and Linux, and no termios struct layout in V.
- used by
- koh_term.c
sqlite/
sqlite/
vendor/sqlite
- size
- 9.4 MB
- lines
- 275,169
- files
- 2
- first save
- f319f052973b 2026-09-23 19:42
- last save
- f319f052973b 2026-09-23 19:42
- saves
- 1
sqlite3.c
vendor/sqlite/sqlite3.c
- size
- 8.8 MB
- lines
- 261,454
- first save
- f319f052973b 2026-09-23 19:42
- last save
- f319f052973b 2026-09-23 19:42
- saves
- 1
- This file is an amalgamation of many separate C source files from SQLite
- version 3.49.1. By combining all the individual C code files into this
- single large file, the entire code can be compiled as a single translation
- unit. This allows many compilers to do optimizations that would not be
- possible if the files were compiled separately. Performance improvements
- of 5% or more are commonly seen when SQLite is compiled as a single
- translation unit.
- This file is all you need to compile SQLite. To use SQLite in other
- programs, you need this file and the "sqlite3.h" header file that defines
- the programming interface to the SQLite library. (If you do not have
- the "sqlite3.h" header file at hand, you will find a copy embedded within
- the text of this file. Search for "Begin file sqlite3.h" to find the start
- of the embedded sqlite3.h header file.) Additional code files may be needed
- if you want a wrapper to interface SQLite with your choice of programming
- language. The code for the "sqlite3" command-line shell is also in a
- separate file. This file contains only code for the core SQLite library.
- The content in this amalgamation comes from Fossil check-in
- 873d4e274b4988d260ba8354a9718324a1c2 with changes in files:
sqlite3.h
vendor/sqlite/sqlite3.h
- size
- 643.5 KB
- lines
- 13,715
- first save
- f319f052973b 2026-09-23 19:42
- last save
- f319f052973b 2026-09-23 19:42
- saves
- 1
- 2001-09-15
- The author disclaims copyright to this source code. In place of
- a legal notice, here is a blessing:
- May you do good and not evil.
- May you find forgiveness for yourself and forgive others.
- May you share freely, never taking more than you give.
- This header file defines the interface that the SQLite library
- presents to client programs. If a C-function, structure, datatype,
- or constant definition does not appear in this file, then it is
- not a published API of SQLite, is subject to change without
- notice, and should not be referenced by programs that use SQLite.
- Some of the definitions that are in this file are marked as
- "experimental". Experimental interfaces are normally new
- features recently added to SQLite. We do not anticipate changes
- to experimental interfaces but reserve the right to make minor changes
- if experience from use "in the wild" suggest such changes are prudent.
- The official C-language API documentation for SQLite is derived
- from comments in this file. This file is the authoritative source
- on how SQLite interfaces are supposed to operate.
- The name of this file under configuration management is "sqlite.h.in".
- The makefile makes some minor changes to this file (such as inserting
- the version number) and changes its name to "sqlite3.h" as
- part of the build process.
.koh) per repo, one line of history where nothing is erased, optional sync to S3 or a local folder.
AGENTS.md
AGENTS.md
- size
- 9.1 KB
- lines
- 179
- first save
- f319f052973b 2026-09-23 19:42
- last save
- dfe5c9f72825 2026-09-28 19:42
- saves
- 15
Koh 3 is a clean rewrite of Koh in V: one SQLite file (.koh) per repo, one
line of history where nothing is erased, optional sync to S3 or a local folder.
docs/koh-kepr-3-master-spec.md is the specification, with
koh-kepr-3-resolutions.md and koh3-addendum-help-screen.md amending it. Read
them before changing anything. Anything not written in it is out of scope for the
current build phases; a new idea is added to the document as a decision first.
README.md
README.md
- size
- 3.7 KB
- lines
- 105
- first save
- f319f052973b 2026-09-23 19:42
- last save
- c99a73d26672 2026-09-28 12:20
- saves
- 5
Version control designed for the solo developer.
v.mod
v.mod
- size
- 123 B
- lines
- 6
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 144
VERSION
VERSION
- size
- 7 B
- lines
- 1
- first save
- f319f052973b 2026-09-23 19:42
- last save
- 8f8891090423 2026-10-01 18:05
- saves
- 141
history
details
Koh
Version control designed for the solo developer.
Most version control is built for teams, with branches to keep people out of each other's way, pull requests to argue in, and merge tools for when two people edited the same line. On your own you need none of that. You need to save your work, see what changed, go back when something breaks, and pick up on your laptop where you left off on your desktop.
That's all Koh does.
koh init
koh save "sketch the parser"
koh status
koh view
koh undo # step back one save, without losing it
koh offer # send your saves to your bucket
koh steal # on the other machine: bring them in
How it thinks
Nothing is erased. Your history is one straight line, and every command adds
to it. Undo, revert and load don't rewind anything. They record a new save
that puts the files back, so the save you stepped away from is still there
tomorrow. The only exception is strip, for the day a secret gets saved,
and it makes you type the path twice before it does anything.
Everything lives in one file. A repo's whole history is .koh, a single
SQLite file at the root, and there's nothing else to maintain. Copy that file
and you've copied the whole history.
Your machines, not a server. Point Koh at an S3 bucket or a folder on a
disk once per machine with koh remote, and every save is offered to it
automatically. If you worked on both machines without syncing, koh steal
combines them file by file. A file changed on only one side just comes along.
A file changed on both sides is shown to you, and you pick which version to
keep. Your version isn't thrown away either way: the save it came from stays
in history.
Safe to hand to an agent. Every command has --json, never waits for
input when nothing is typing, and exits 0, 1 or 2. Saves record which agent
made them and in which session, so koh undo --session can take back an
agent's whole run in one step. A person has to be at the keyboard to strip.
Small on purpose. Koh 3 has 17 commands, down from Koh 2's 45, and a hard ceiling of 10,000 lines of V. A feature that doesn't fit gets cut, so one person can still read all of it.
Setting up sync
koh remote # asks: a folder, or an S3 bucket?
It tests the remote before saving anything. Scripts can skip the questions:
KOH_ACCESS_KEY=... KOH_SECRET_KEY=... \
koh remote s3 https://s3.fr-par.scw.cloud my-bucket fr-par
koh remote folder /Volumes/usb/koh
Or write the two files yourself. koh man remote shows the format.
~/.config/koh/remote kind, endpoint, bucket, region (or path)
~/.config/koh/credentials access_key, secret_key, mode 600
In your prompt
shell/koh3.plugin.zsh puts the repo in your zsh prompt and adds tab
completion:
kiln · v2.1.0 · 6 saves · 4.2 MB !
→
! means unsaved changes, and ⚑ means the save you're on has been flagged.
Source it from ~/.zshrc. The comments at the top cover Starship,
Powerlevel10k and using your own prompt.
Status
Koh 3 is a rewrite of Koh 2 in V, for macOS and Linux. While it's being built
the binary is called koh3. At the cut-over it becomes koh, Koh 2 becomes
koh2, and koh migrate converts a Koh 2 repo in place. The specification
is /Users/june/Downloads/Koh 3 — God Document.md.
Building
v -o build/koh3 src/koh3.v # or -prod for a release build
v test src/ && v test tests/
v fmt -verify src/ tests/
Koh is pinned to V master at b9a2d87, because V master can break it. SQLite
3.49.1 is vendored and compiled in, so there are no other dependencies.
AGENTS.md has the install steps for the pinned V, the Linux notes and the
layout.