Repository navigation
Berth v0.2.0
v0.2.0
Berth decides who gets your GPU. Engines, games and GPU apps lease the card instead of grabbing it, so two of them never load at once and crash each other. One Go binary, no cloud account, nothing else to install.
v0.2.0 is the first release since v0.1.0. It adds four new areas: a pinned git suite for managing ComfyUI installs, a gateway with a wake plane that opens your engines' web UIs from a bookmark, a model library with pull, shelves, storage floors and CivitAI, and an overhaul of the harbor UI for phone and desktop. Windows becomes a working experimental node, and games and other apps can take the card through holds and claims.
Engine suite
berth engine install NAMEmanages a ComfyUI install as a pinned git suite:--adopt PATHrecords an existing checkout,--pathclones a fresh one. The core, ComfyUI-Manager and each node pack are separate components, each pinned to a git commit.updatepins components to newer commits, keeps the old pin as the rollback snapshot, and adds node packs with--pack.rollbackswaps a component back to its previous commit.removedrops the state entry, or the directory too with--delete --yes.showprints the install.- Update and rollback are refused while jobs run (the handoff happens at the job boundary) or when a component's tree is dirty.
- State lives in a new
engines.tomlbesideberth.toml. Each install derives an engine that appears inberth engine check,berth statusand the gateway's wake page, and itsextra_model_paths.yamlnames the model roots fromberth.toml. The daemon, gateway and config commands read the suite-merged config.
Gateway and wake plane
berth gatewayserves one OpenAI-compatible port for every engine. A request naming a model an engine serves goes to that engine, and a stopped engine cold-starts under a lease: Berth drains the holder, waits, and proxies the stream.- The node's API key is created on first start (
~/.config/berth/api.key, mode 600, printed by the newberth key), and refused when the file is group- or world-readable. Non-loopback Host names and browser origins are refused before resolution. - A start waits for the card no longer than
--ready, and a cold start without RAM headroom is refused.berth config checkrejects a model served by two engines. --allow-hostnames a same-machine reverse proxy's hostname for a loopback gateway.berth gateway --gui-listenserves/gui/<engine>for every engine that has both a start command and aguikey inberth.toml. A visit to a running engine redirects to its web UI; a stopped one shows a page that names the card's holder, shows the broker's progress behind a Start button, then opens the UI.- The
/guiindex lists every engine with its state and a launch button, and opening an engine that already answers goes straight to its UI without a start cycle.
Model library and pull
berth pull hf:org/repo[:quant|file|glob][@rev]resolves the revision to a commit, downloads the matching GGUF (every split part plus the vision projector) and checks each file against the size and sha256 the Hub publishes before it moves into place. Interrupted pulls resume by Range request.berth verifyre-hashes pulled models against their manifest with no network, and exits 1 on a missing, truncated or changed file.berth modelslists every model on the machine: GGUF via a built-in header reader, safetensors folders, the Hugging Face cache, LM Studio and Ollama. It shows quants, usage from the harbor's request log (--usage 30d, including a running llama-swap's resolved config) and the new SHELF column, filterable with--shelf.berth models show NAMEprints one model's header, andberth models export ollamawrites a Modelfile and runsollama create.--dry-runprints both; a split GGUF is refused until merged.- Shelves: every model lands on a shelf (chat, image, audio) from what the file states, or from a shelf declared for its root. A file that states nothing is shown unshelved, not guessed. A scan leaves a snapshot at
.berth/catalog.jsoninside each root, so a second machine reading the same root sees the same catalog. - The floor:
berth storagereports each root's filesystem, its free space against the[library]floor, the other operating system it shares with, and what it can share (hard links, symlinks, reflinks). A root under its floor fails the check, and a pull is refused when it would leave the root under the floor. A root whose space cannot be measured says so instead of pretending to guard. - CivitAI:
berth pullreads a version id, a model id for its latest version, or the site's own URLs. Files land under<dir>/civitai/<model-slug>/and are checked against the hash the site publishes.berth civitai search QUERYandberth civitai versions MODEL_IDfind the ids a pull takes; public models need no key,--token-envnames the variable holding one for gated results. - One transfer (part-file resume, size and sha256 checks, retry with backoff) serves every source, and one manifest record type covers Hub and CivitAI pulls.
Harbor UI
- The harbor is rebuilt: sub-navigation with scroll-spy and folding panels, keyboard shortcuts with a help dialog, a log filter with live counts and jump-to-latest, dismissible alert cards, a sortable departures board, ticket copy and deep links, honest empty states, and a measured AA contrast floor. Repaint gates stop the 3 s poll rebuilding the timeline, machine and berth charts.
- Never-started engines now read OFFLINE in grey; DOWN (UNRESPONSIVE) in amber still marks a stopped engine. The poll is quieter, accessibility gaps are closed, and the offline card is restored.
- A new deep-water repaint: a tokenized teal-tinged dark theme, one color source for panels and charts, and a complete KPI strip.
- Phone refresh: one 56 px rail plus a bottom nav with an active mark and a menu sheet, 44 px touch targets on every control, chip pickers and a 16 px filter field so iOS stops zooming, the departures board as cards with a wrapping log row, chart axis words moved to an HTML overlay so 2 px text never renders at 375 px, and one shape-and-word vocabulary so every state reads without colour.
- The About tab names the navigation as it ships and lists what is still coming.
Engines and runner
- Windows is now a working experimental node: parent and start-time attribution from the process table,
berth runin its own console process group and job object so a drain stops the engine's whole process tree, a built-in claims pack that covers Steam, Epic, GOG, EA, Ubisoft, Xbox and Battle.net games by install folder, and the socket in%LOCALAPPDATA%\berth. berth holdpins the card to you at the new hold priority, andberth run --pinneddoes the same for an app that must not be drained.- Claims cover work Berth does not start. The built-in pack holds the card while Steam, Lutris and gamescope games run, and tracks Blender, DaVinci Resolve, OBS and Kdenlive so their memory counts against the card instead of raising a stowaway report.
[[claim]]rules inberth.tomlcover the rest, by name, command line or launcher.berth claimslists the rules and what they match;berth statusshows active claims and pinned leases. - ComfyUI drains by unload: once its queue is empty,
berth runposts/freeand verifies the models left VRAM.--keep-comfyui-up(with--drain-comfyui, orkeep_comfyui_upon a comfyui engine inberth.toml) leaves the server running on the freed card and records the keep-up drain as an unprotected run. - When a waiter cannot be granted and an unprotected ComfyUI squatting on at least 1 GiB holds the card, the broker asks it for
/freeat its job boundary and holds the waiter until the squat drops, instead of granting the card over it. - A juggle guard stops two equal-priority engines draining each other, and engines rank by a configured order or by card-hours. The broker returns error codes a client can branch on.
- A fully contested card makes the broker wait instead of granting.
- The collisions board survives a daemon restart, and the harbor shows 5m, 15m, 1h, 24h and 7d windows.
- The socket server now drops slow consumers with write deadlines.
- The llama-swap patch in
contrib/wraps every model inberth run, wired in one pass; the roster lives in one README and one command. - A
berth runwith no flags reads the[[engine]]entry matching--as(or--group) for priority, needs_mib, drain settings andkeep_comfyui_up. A flag set on the command line wins over the entry, and the merge is printed so file and flags can never disagree silently. - Kokoro-FastAPI is read and discovered on its default port (health, model list, voice count, default voice), and every engine now reports a kind.
Config
- New keys in this release:
keep_comfyui_upon a comfyui engine, the engineguikey, the enginekindkey (llm, image, tts, stt, other; custom engines name their own),[library] free_floor(default 10 percent, 0 turns the guard off),[[library.root]]entries naming a root's shelf and its other OS,[[claim]]rules, and the suite'sengines.tomlstate file. - Defaults are materialised in the resolved config.
berth config checkgrows--configand--strict, andberth config showprints the resolved config in human, json, yaml or toml.
CLI
- One command tree, one output contract (
--formathuman, json, yaml, plus toml on config show) and one exit-code contract (0 done, 1 validation, 2 system).-vand-qapply to every command. - New commands since v0.1.0:
gateway,key,hold,claims,pull,verify,models(withshowandexport ollama),storage,civitai searchandcivitai versions,skill installandskill show, andengine check,install,update,rollback,remove,show. berth skillships an agent skill embedded in the binary that teaches coding agents to use Berth: read the card, ask for it, holds, claims, the gateway, load failures.berth skill installwrites it to~/.claude/skills,~/.agents/skillsand~/.config/opencode/skills(or--dir), keeping a different existing file asSKILL.md.bak.berth engine checkreads every configured engine once, without a daemon.berth exportmoves its file format to--as.go installand checkout builds report the module version (or the tag plus+dirty) instead of0.1.0-dev; release builds still stamp the version.
Docs
- The README leads with what Berth does, grouped by the command that does it, with a quick start. The support matrix and roadmap match what is merged: holds and claims are done, Windows is experimental.
- An animated banner and a how-it-works diagram replace the old header; the first screen is shorter and the feature list moves below it.
- README sections follow the new work: models, usage and Ollama export; the library's sources, shelves, floor and storage; the suite paragraph. Previews were re-shot from the refreshed harbor.
Upgrade notes
From v0.1.0:
- New commands to look for:
gateway,key,hold,claims,pull,verify,models,storage,civitai,skill, and the sixenginesuite subcommands. - New config keys:
keep_comfyui_up,gui,kind,[library] free_floor,[[library.root]],[[claim]], and theengines.tomlstate file.berth config checkrejects an unknownkindon a custom engine and a model served by two engines. berth runwith no flags now reads the matching[[engine]]entry fromberth.toml; a flag you set wins, and the merge is printed. If your unit relied on the daemon's old defaults, pin the flags explicitly.- A pull is now refused when it would leave its destination root under
[library] free_floor(default 10 percent). Setfree_floor = 0to restore the old behavior. - The gateway is loopback-only by default and refuses browser origins;
--allow-hostis the opt-in for a same-machine reverse proxy. - A ComfyUI drained with
--drain-comfyuiis unloaded through its/freeendpoint and verified; a squatting ComfyUI can delay a grant while it frees. - The socket server drops slow consumers; a client that stops reading can now be disconnected by the daemon.
- The harbor shows 5m/15m/1h/24h/7d windows, never-started engines read OFFLINE, and the UI was restyled end to end (deep-water theme, phone layout).
- On a Windows node the socket lives in
%LOCALAPPDATA%\berth;berth hold,--pinnedand claims work there.