- Go 90.3%
- CSS 4.8%
- HTML 4.6%
- JavaScript 0.3%
| .github | ||
| cmd | ||
| docs | ||
| internal | ||
| .gitignore | ||
| go.mod | ||
| README.md | ||
Harbor
Harbor is a workspace-first version control prototype.
The short version: Git is excellent at tracking file history, but large multi-component workspaces often need a higher-level view of the whole project. Harbor treats the workspace itself as the main unit of state. A snapshot captures the files, the component graph, contracts, and enough operation history to inspect, undo, sync, and repair the workspace later.
Harbor is ready for careful dogfooding on real projects with backups. It is not production-ready yet. The current implementation is best for single-user or trusted small-team testing where you control the storage and HTTP endpoints.
What works today
Harbor currently supports:
- local repositories with
.harbormetadata, - snapshots, logs, status, diffs, rollback, and undo,
- local branch refs,
- component manifests and dependency graphs,
- compatibility contract metadata,
- filesystem remotes with publish, fetch, sync, and clone,
- HTTP/HTTPS remotes for fetch, sync, clone, component update, and authenticated publish,
- the
serverexecutable, which exposes HTTP refs/objects plus styled browser pages with SSE live refresh and global JSON auth ACLs, - clone-time materialization filters for sparse workspaces,
- local ignore/include/exclude rules,
- object inspection,
- operation history,
doctorand conservative repair flows.
The big missing pieces are rich hub discovery/administration, review workflows, merge/conflict reconciliation, packfiles, and scale-oriented transport optimization.
Build it
You need Go 1.26.2 or newer.
go build -o bin/harbor ./cmd/harbor
go build -o bin/server ./cmd/server
Or run directly while developing:
go run ./cmd/harbor --help
go run ./cmd/server --help
Start a workspace
On the first interactive Harbor command, Harbor asks for your name and email if global identity config is missing. It saves them in harbor/config.lob under your OS user config directory and reuses that identity for snapshot authors and first-run server setup. Non-interactive commands do not block for prompts; they keep using environment defaults.
From an existing project directory:
harbor init
harbor status
harbor snapshot "initial import"
harbor init creates .harbor. harbor snapshot records the current workspace as immutable objects and moves the current branch ref to that new workspace snapshot.
If you already have a tree on disk and want Harbor to accept it as the current state without writing a message, use:
harbor adopt
adopt is useful for importing or accepting externally changed workspace state.
Harbor snapshots use portable defaults without extra config: regular file bytes are stored exactly as written, text files must use LF line endings, unsafe cross-platform path names are rejected, case-insensitive path collisions are rejected, symlinks are not snapshotted by default, and file permissions are normalized to ordinary file or executable file. That keeps object hashes stable across macOS, Linux, and Windows without autocrlf-style rewrites.
Daily local workflow
harbor status
harbor diff
harbor snapshot "change terrain loader"
harbor log
harbor oplog
status and diff compare the worktree to Harbor HEAD. log shows first-parent snapshot history. oplog shows operations such as snapshot, fetch, sync, rollback, undo, clone, repair, branch changes, and component updates.
If you make a mistake:
harbor rollback HEAD_OR_WORKSPACE_ID
harbor undo
rollback moves to a specific workspace snapshot. undo walks operation history and restores the previous effective workspace state for HEAD-changing operations.
Branches
harbor branch feature-a
harbor branch list
harbor branch switch feature-a
harbor branch delete feature-a
Branches are workspace refs. Switching branches requires a clean worktree and restores that branch's workspace snapshot and manifest graph.
Remotes
Filesystem remotes can publish and fetch:
harbor remote add origin /srv/harbor/my-project
harbor publish origin
harbor fetch origin
harbor sync origin
publish copies missing typed objects and updates the remote workspace ref. fetch copies objects and records a local remote ref without changing your worktree. sync fetches and materializes the remote workspace into a clean local worktree.
HTTP/HTTPS remotes can read public repositories without auth, read private repositories with Basic auth, and publish when the authenticated user has writer or stronger access:
server --http 127.0.0.1:8080
harbor remote add origin http://localhost:8080/sharkk/harbor
harbor publish origin
# or keep the first publish private:
harbor publish --private origin
harbor fetch origin
harbor sync origin
Interactive remote add prompts for username/password when no saved credentials exist, then stores them locally for the HTTP root (http://localhost:8080 here), so every repository on that server can reuse them. Prompts use the controlling terminal when available, even if stdin is piped, and password input is hidden. Use --user USER --password PASSWORD to seed the same store without prompts. If a saved credential fails during clone, fetch, sync, or publish, Harbor prompts once for replacement credentials, retries, and keeps them only when the retry succeeds.
Bearer-token publish remains available as a compatibility override with harbor remote add --token TOKEN NAME URL or HARBOR_TOKEN=TOKEN. Tokens are still local workspace secrets in .harbor/remotes.lob; username/password credentials live in Harbor's global credentials.json, owner-only (0600), outside any workspace. Use HARBOR_AUTH_USER and HARBOR_AUTH_PASSWORD for process-only credentials.
For normal hosted work, prefer username/password auth and repository ACLs. Tokens are bootstrap compatibility only.
Clone
harbor clone /srv/harbor/my-project my-project
harbor clone http://localhost:8080/sharkk/harbor my-project
Clone initializes the target, restores origin, records the remote ref, materializes files, and writes a clone operation.
You can choose what materializes at clone time:
harbor clone --full SOURCE target
harbor clone --component engine SOURCE target
harbor clone --include src/ SOURCE target
harbor clone --exclude assets/raw/ SOURCE target
Those flags write local materialization rules to .harbor/local.lob, so the workspace stays clean even when some tracked files are intentionally absent.
Serve Harbor over HTTP
server --http 127.0.0.1:8080
server --http :8080 --root /srv/harbor-hub
The dedicated server entrypoint is ./cmd/server; harbor serve remains a compatibility wrapper over the same shared runner.
Create password hashes for auth JSON with stdin:
read -r -s HARBOR_PASSWORD
printf '%s' "$HARBOR_PASSWORD" | harbor auth hash-password --password-stdin
This serves:
- a global Harbor hub, not the current workspace,
- repository URLs such as
/sharkk/harbor, - loose object/ref endpoints under each repository URL for HTTP clone, fetch, sync, component update, and authenticated publish,
/assets/style.css,/assets/live.js, and/assets/icons/*.pngfrom embedded frontend files,/as theref.html-style feed landing page with user summary, recent activity, visible repositories, recently updated repositories, repository topics when present, and live SSE state,/exploreas a readable repository index,/<org>/<repo>/workspaces/<branch>as aref.html-style repository page adapted for Harbor workspaces, with branch/workspace navigation plus component and file browsing,/<org>/<repo>/workspaces/<branch>/files/<path>as tree-backed file content,/<org>/<repo>/settingsas an owner-only repository subtitle and visibility form,/<org>/<repo>/issuesand/<org>/<repo>/issues/<number>as issue list/detail pages with signed-in create, comment, close, and reopen actions,/eventsand/<org>/<repo>/eventsas SSE streams so hub, repository, login, account, and settings pages can refresh when visible state changes.
The server stores hosted repositories under Harbor's global config directory by default, in harbor/hub/repositories/<org>/<repo>. --root overrides that hub storage root. Server identity and access also live in Harbor's global config directory, not in any workspace. By convention, server and harbor serve use harbor/auth.json under the platform config dir. If it is missing, Harbor prompts for optional first admin username and password. Password input is hidden. Blank username keeps the username derived from global identity; blank password generates a random initial password printed once. Harbor then creates one admin user with a server-local usr_... ID and optional display name from global identity. Use --admin-user or --admin-password on that first run to skip either prompt and set login credentials directly. User-provided passwords are not printed back. After that, browser pages use a normal /login form with a session cookie, while HTTP remote endpoints keep using Basic auth plus repository ACLs. The web UI uses a nautical, textured Harbor skin with Home and Explore nav, a signed-in avatar menu, a ref.html-style home feed, embedded local CSS/JS, and FarmFresh PNG icons. New repositories are public on first publish by default and readable without login; use harbor publish --private for a private first publish. Successful publishes register the repository in auth.json, grant the publishing user owner, track repository counters plus per-user star, watch, and fork state, and increment that user's per-day publish contribution count in harbor/hub/contributions.json. Owners and server admins can edit the repository subtitle, topics, and public/private visibility from the web Settings page. Users may create repositories under their own identity path, such as /sky/test. Sign in on the web UI to see private repositories. Star and watch buttons toggle per-user state; fork creates one user-owned hosted copy with the source objects and workspace refs. Issues are repository-local hub metadata with signed-in creation, comments, close/reopen state changes, searchable open/closed/all lists, default labels with label assignment, @ mention links, #hash links to matching Harbor objects, and synchronized open-issue counters. Repository and workspace pages use the reference repo layout: Harbor / owner / repo (workspace) breadcrumbs, optional subtitles that disappear when empty, repo-only titles, title-row star/watch/fork buttons that submit signed-in, CSRF-protected actions, an Issues tab with the full issue tracker, and a dedicated Components tab with a muted component-count pill, workspace selector, clone dropdown, owner-only navy Add file control, latest workspace strip with a registered display name or trimmed author name, ago time, and snapshot count, 6-character linked hash pills, and file rows with last-touch snapshot message and ago time, plus a safe root README.md preview. Every HTML page carries SSE state metadata and refreshes through /events or the repository-scoped events stream when visible hub, repository, contribution, issue, or workspace state changes. The web frontend lives in embedded files under internal/harbor/web/: Go only wires templates, view models, SSE state tokens, and asset serving. ACL subjects may be user IDs, usernames, organization names, anonymous, or authenticated, so a repository can allow public reads, authenticated-user publishing, or stricter named-user writes. The auth file must be owner-only (0600), must not be a symlink, and stores password hashes only. The server does not expose arbitrary local worktree files, local workspace config, workspace remotes, oplog, SSH, or review workflows.
Harbor's next server work is a fuller HTTP hub: repository discovery and review flows. Harbor will keep that implementation in Go's standard library. The server should stay plain HTTP; put it behind your web server or reverse proxy for SSL/TLS.
Components
Harbor workspaces can describe components in .harbor/manifest.lob:
harbor component add \
--name engine \
--path engine \
--source /srv/harbor/engine \
--role library
harbor component add \
--name game \
--path game \
--source /srv/harbor/game \
--depends engine=compatible
harbor component list
harbor graph
harbor status reports pending manifest-only graph edits as manifest changed.
Run harbor snapshot to record component graph changes even when tracked files are
unchanged.
You can update one component from its source:
harbor update engine
Component sources can be filesystem remotes or read-only HTTP/HTTPS remotes.
Contracts
Contracts are lightweight compatibility metadata attached to components:
harbor contract add \
--component engine \
--name api \
--compatibility v1
harbor contract add \
--component game \
--name game-api \
--compatibility v1 \
--requires engine=v1
harbor contract list
harbor contract validate
Current validation checks ownership, duplicate names, required components, compatible dependency edges, and required compatibility labels. Deep ABI/schema/effect validation is still future work.
Local materialization and ignore rules
.harbor/local.lob can keep local-only noise out of status/snapshot and can control sparse materialization:
[ignore]
patterns = "
build/
.tmp/
"
[include]
patterns = "
engine/src/
"
[exclude]
patterns = "
assets/raw/
"
Ignore patterns affect local-only files. Include/exclude patterns affect which tracked remote paths should exist in the worktree.
Inspect and repair
harbor inspect HEAD
harbor inspect <object-id-or-prefix>
harbor doctor
harbor doctor --repair
inspect prints deterministic summaries for Harbor objects. doctor checks layout, refs, configs, object hashes, object links, and operation history. Repair is conservative: it fixes cases Harbor can prove safe, and refuses cases that would require guessing.
Suggested dogfood rules
Use Harbor on real projects, but keep it boring:
- Keep a Git repo or backup beside the Harbor workspace.
- Start with filesystem remotes before relying on HTTP serving.
- Run
harbor statusbefore destructive-looking commands. - Prefer
harbor snapshot "message"after each logical change, or let Harbor summarize the diff when the message is obvious. - Run
harbor doctorafter sync, clone, and repair experiments. - Prefer normal username/password hub auth; use bearer tokens only for compatibility testing.
Project status
Harbor is still a prototype. Its object model, CLI, recovery story, and read-only hosting are in place enough to test the workflow end-to-end. The next big step is real-world feedback: try it on a real workspace, write down what feels awkward, and keep an eye on correctness, performance, and recovery behavior.
The design notes live in docs/harbor.md, and the Lobster config format is documented in docs/lobster.md.