Your work, in public
Kepr is a self-hosted website for your Koh projects. Visitors can read your code and history, download releases, or report problems. A profile and recent activity bring your projects together in one library.
Koh keeps the history on your machine. Kepr reads the history you offer to your storage and makes it available on the web. You keep working in the terminal.
Explore a project
Open Koh, Kepr, or Nina to explore a project. Its timeline shows when work happened. In the atlas, you can filter files, browse folders, and read descriptions taken from the code. Open a save to read its message, see which files changed, and inspect the code at that point in its history.
Source archives contain the latest tree or the tree at a particular save. Published builds have versioned downloads, release notes and checksums. Visitors can report bugs or ask questions through public issues without an account. Each reporter gets a private follow-up link for returning to the conversation.
To download Nina's code with its Koh history:
koh steal kepr.uk/nina
cd nina
koh view
Run koh steal inside that repository later to bring in new saves from its public source. Download a source archive if you only need the files.
How Koh and Kepr fit together
Koh stores your project's history in a local .koh file. An offer sends saves and file objects to the folder or S3-compatible bucket configured as your remote. Every repository on the machine uses that remote.
Kepr reads the same storage, checks the incoming history, and keeps a local copy to serve pages. It syncs every two minutes, or immediately when you request a sync in the console. Your development machine can be offline while people browse the site.
Choose which repositories are public in Kepr's console. Offering a repository to the bucket does not make it public on the website. Private repositories stay out of public pages, downloads and feeds.
Kepr leaves Koh's saved history unchanged. It stores its own settings, issues and download counts in its database, keeps its own files under .kepr/ in the bucket, and deletes published build files when you ask it to.
Connect your machine
If you operate this Kepr, connect Koh once:
koh remote kepr.uk
Koh opens the sign-in page. Sign in as the operator, copy the one-time code, and give it to Koh. Koh tests the storage settings it receives before saving them on your machine. Offers then go directly to the bucket; the website does not carry your history between the machine and storage.
Inside a project, save your work and offer it:
koh save "describe the change"
koh offer
Open repos in Kepr's console, select the repository, and make it public. You can set its description, homepage and category there. After the next sync, its code and history are available at /<repository-name>.
This sign-in connection is for the operator's machines. Visitors can browse public projects and steal them over HTTPS without signing in.
Publish releases
Add a koh.build recipe with your project's build command, supported platforms and output paths. Keep the version in the project's manifest or VERSION file. Test the builds locally with koh build or koh build --all.
To publish:
koh offer --builds --notes "Describe what changed in this release"
Koh builds every configured platform before uploading any release files. It uploads the files and checksums, publishes the release record, then moves the latest pointer. Published versions cannot be overwritten. A corrected build needs a new version.
Kepr displays the release on the builds page and serves its downloads and update feeds. Applications can use those feeds to find their newest release; koh update uses Koh's own feed here. In the console, you can edit release notes, hide a build or delete its files.
Run your own Kepr
Each instance has one operator account and presents that person's projects. Run Kepr on your own domain, using your own storage.
Requirements
- A server with Bun 1.3 or newer.
- An S3-compatible bucket containing your offered repositories (
koh remote s3 …, thenkoh offer). - A key for that bucket that can read and write.
- A domain and a reverse proxy on the same machine to terminate HTTPS.
Install and set up
Unpack Kepr's source on the server, then run:
bun install --production
PORT=3000 bun run start
On the first run, Kepr prints a setup code in the terminal and serves only /setup. Open that page, enter the code, and choose your admin password, domain and bucket. Use an S3 bucket and its key, or a Koh folder remote to try Kepr locally.
Kepr tests the bucket and writes the configuration to kepr.toml, readable only by the user running Kepr. It stores its data under data/, then takes you to sign in. Ten wrong codes lock setup until you restart Kepr with a new code.
After setup, change settings in the console. Use bucket for the storage connection, email for email settings, backups for a backup bucket, and account for your password and domain. These changes do not require editing a file.
The port defaults to 3000. Kepr syncs from the bucket every two minutes and renders pages from its local copy.
Reverse proxy
frontend web
bind :80
bind :443 ssl crt /etc/haproxy/certs/code.example.org.pem
http-request redirect scheme https unless { ssl_fc }
option forwardfor
default_backend kepr
backend kepr
server kepr 127.0.0.1:3000
Run the proxy on the same machine as Kepr. Kepr trusts X-Forwarded-For only from loopback and uses its rightmost entry for rate limits. Use option forwardfor. The alternative, option forwardfor if-none, passes a visitor's own header through.
Admin console
Sign in at https://<domain>/sign-in. The console requires HTTPS on the configured domain, with plain HTTP allowed when the domain is localhost. Sessions last 30 days. Repeated wrong passwords pause sign-in for 15 minutes.
The overview shows repository visibility, open issues, sync problems, backups and bucket checks.
In repos, publish or hide repositories and set their category, homepage, description and details. You can request an immediate sync or delete stored tarballs. For each build, you can see download counts, edit notes, hide it from the site and feeds, or delete it from the bucket.
You can also rename a repository. The history, settings and counts move to the new name, old links redirect, and Koh follows the rename on each machine's next save or steal.
You can hide files and folders from every page, the statistics and tarballs. Kepr also sends the list to .kepr/hidden/<repo> for Koh.
The other console sections cover:
- Issues: reply, close or reopen an issue, change its type, or hide spam. Reporters' emails are visible only here.
- Notifications: choose which notices to receive for new issues, follow-ups, and failing syncs or backups.
- Email: configure the SMTP server for notifications, send a test email, and check the delivery queue.
- Bucket: configure an S3 bucket and its keys, or a folder remote. Kepr tests S3 settings before saving them.
- Backups: download any kept backup, make one now, read the restore instructions, or set a backup bucket to receive a copy of each backup.
- Profile: set your handle, bio, location, website and building-since date. Profiles live at
/@<handle>;/<name>is a repository. - Site: set the site name, tagline, branding text and support page. You can also ignore names such as
.agentorAGENTS.mdacross every repository. Matching files and folders are hidden at any depth, from pages and tarballs. - Account: change the admin password or domain, or sign out everywhere else. Changing the password signs out other sessions.
Data and backups
In data_dir |
Holds | Rebuilt from the bucket? |
|---|---|---|
kepr.db |
Settings, issues, download counts | No |
assets/ |
Your signature image and branding | No |
mirror/ |
Repo copies | Yes |
backups/ |
The last 14 daily backups | No, copy them off the machine |
Kepr keeps built tarballs in the bucket under .kepr/tarballs/.
Kepr backs up kepr.db and assets/ once a day. It makes the first backup just after startup. If you set a backup bucket in the console, Kepr copies each backup there and keeps the newest 14. Otherwise, download backups from the console.
To restore, stop Kepr, unpack a backup into an empty data_dir, and start it again:
mkdir data && tar -xzf kepr-backup-20260926T031500Z.tar.gz --strip-components=1 -C data
Sign in again after restoring. The first sync rebuilds the mirrors.
Updating
Replace the source, run bun install --production, and restart Kepr. If the new version cannot read an old mirror, it reports the problem. Delete that mirror file and the next sync will rebuild it.