Kuro is a local-first version control system built in Go with SQLite.
This repository focuses on the core engine and CLI, with a remote API under development.
Kuro (黒) means “black” in Japanese — a clean slate and deliberate starting point.
- Overview
- Project Structure
- Core Concepts
- Features
- Getting Started
- CLI Usage
- Configuration & Storage
- Remote API
- Development Notes
- License
Kuro explores a transparent, explicit VCS design:
- Repository state is stored in a single SQLite database
- Refs, snapshots, and config are first-class concepts
- The CLI is a thin orchestration layer over the core engine
kuro/
├── core/ # Core VCS engine (SQLite-backed)
├── cli/ # Command-line interface
├── api/remote/ # Remote API server
├── go.work
└── README.md
- Refs: branch names that point to snapshots (or remain unborn)
- Snapshots: immutable commits captured as explicit records
- Objects: content-addressed blobs stored in SQLite
- HEAD: always points to a ref (never a detached orphan)
- Initialize a repository
- SQLite-backed storage (refs, snapshots, objects)
- Branch create / list / delete
- Add & stage files
- Commit snapshots
- Checkout refs or snapshots (workspace reset with
--ws) - Status & logs
- Diff for staged files (
diff) - Raw SQL queries against the repo database (
sql) - Config and auth management
- Remote management and push
- Identity check (
whoami)
- Go 1.19+ (or your target Go version)
git clone <repository-url>
cd kuro/cli
go build -o kuro
./kuro init
This creates a .kuro/ directory containing the SQLite database and metadata.
./kuro add .
./kuro commit -m "Initial snapshot"
./kuro status --stage
With --stage, Kuro lists staged files and unstaged files (prefixed with -).
./kuro diff
./kuro diff -f path/to/file
./kuro logs
./kuro logs --branch main
./kuro branch list
./kuro branch create dev
./kuro branch delete dev
- Switch HEAD only (no workspace changes):
./kuro checkout dev
- Reset workspace to snapshot:
./kuro checkout dev --ws
./kuro sql "SELECT name, snapshot_hash FROM refs"
.kuro/kuro.db— SQLite database.kuro/.kuroignore— ignore rules
Stored at:
~/.kuro/config.json
Fields:
name— author name used in commitstoken— auth token used for remote API
Set via:
./kuro config --name "Your Name"
./kuro config --token "your-token"
Default entries created on init:
.kuro
.git
node_modules
dist
build
The remote API is a Gin server backed by PostgreSQL.
See .env.example in:
/(root)api/remote/cli/core/
The remote API uses:
DATABASE_URL(required)REMOTE_HTTP_ADDRREMOTE_HTTP_SHUTDOWN_TIMEOUTREMOTE_LOG_LEVELREMOTE_LOG_DEV
All /api/* endpoints are protected by auth middleware:
Authorization: Bearer <token>
or- session cookies (
authjs.session-token/__Secure-authjs.session-token)
Base: http://localhost:8080/api
GET /health— health checkGET /version— build infoGET /ping— returns auth user context
GET /repositories?name=&user_id=— list repositoriesGET /repositories/:id— get repository by idPOST /repositories— upload repo database
Upload requirements:
Content-Type: application/octet-streamAuthorization: Bearer <token>X-Remote: <user>/<repo>
GET /repositories/:id/refs— list refsGET /repositories/:id/refs/:ref— get ref by name
GET /repositories/:id/objects— list object hashesGET /repositories/:id/objects/:hash— get object content
GET /repositories/:id/snapshotsGET /repositories/:id/snapshots/:snapshot_idGET /repositories/:id/snapshots/:snapshot_id/filesGET /repositories/:id/snapshots/:snapshot_id/files/*file_id
GET /users/me— current userGET /users?name=&page=&limit=— list users (paged)
- This repo uses Go workspaces (
go.work) for local module development. - The CLI depends on the core module.
- The remote API is isolated under
api/remote.