repoman
Per-project Incus containers + opinionated NFS/ZFS backup. v0.1.
Build
reefc build
Produces ./build/repoman.
Test
for t in tests/test_*.reef; do
echo "== $t =="
reefc run "$t" || exit 1
done
Install
System-wide via Makefile (uses reefc build under the hood):
make
sudo make install # installs to /usr/local/bin/repoman
Quickstart
# First run creates ~/.config/repoman/repoman.toml with sane defaults.
repoman --help
repoman new isurus --repo isurus-project
repoman sync --dry-run
repoman list
Subcommands
| Subcommand | Description |
|---|---|
new <name> [--repo <dirname>] [--image <image>] |
Launch an Incus container and bind a local repo into it. (Use repoman setup --with-llm first if you want LLM stack wiring.) |
sync [name] [--no-delete] [--dry-run] |
Mirror local repos to NFS backup via rsync. |
list |
Print a table of all registered projects (read-only). |
status [name] |
Show project state from registry + live incus query. |
remove <name> --yes [--keep-incus] |
Delete the incus container and registry entry. --yes required. |
shell <name> [--cwd <path>] |
Open a bash login shell inside the project's container (replaces repoman). |
--help / -h / help |
Show usage and subcommand list. |
--version / -V |
Print version string. |
Setup wizard
First-time host bootstrap (idempotent — safe to re-run):
repoman setup # interactive
repoman setup --non-interactive # accept defaults
The wizard creates the Incus project repoman, detects your host LAN IP (used by
profiles that wire containers to host services), and writes the initial registry.
After setup, install the vendor profile library:
repoman profile install --all
Profile library
repoman ships a vendor profile library at /usr/local/share/repoman/profiles/.
v0.4 includes three profiles:
claude-share— bind~/.claudeand~/.local/bin/claudeinto containers
so they share the host's Claude CLI auth, history, and plugins.llm-share— bind/usr/local/bin/ollamaand~/.ollamainto containers,
setOLLAMA_HOST=http://<host-lan-ip>:11434so containers reach the host's
ollama daemon over LAN.dotfiles— bind~/.gitconfigand~/.hgrc(extend with your own).
Manage profiles via repoman profile:
repoman profile list
repoman profile install <name>
repoman profile install --all
repoman profile diff <name> # show drift between file and incus state
repoman profile show <name> # print rendered YAML
repoman profile remove <name> # remove from incus (file untouched)
Customizing profiles
To override a vendor profile, copy it to your user dir and edit:
cp /usr/local/share/repoman/profiles/dotfiles.yml ~/.config/repoman/profiles.d/
$EDITOR ~/.config/repoman/profiles.d/dotfiles.yml
repoman profile install dotfiles # applies the user version (shadows vendor)
User profiles in ~/.config/repoman/profiles.d/ always win over vendor profiles
of the same name. repoman profile list shows the active source for each.
Migrating from v0.3
If you ran repoman setup --with-llm on v0.3, your registry is at schema 2 and
includes a [defaults.llm] block. v0.4 reads that block on first load, extracts
the ollama_url's host portion into [host].lan_ip, and writes the registry as
schema 3 on the next save. No action required — the migration is automatic and
lossless for the one fact that's still useful.
The --hermes / --no-hermes / --purge-hermes flags are gone (those were
already reverted in v0.3 before tagging). Hermes (and similar agents that need
per-container installs) is the user's responsibility: shell into the container
with repoman shell <name> and run the install yourself.
Smoke test (requires Incus + NFS)
# In an existing repo dir under ~/repos:
repoman new test-foo
repoman sync test-foo --dry-run
incus delete --project repoman test-foo
Output and logging
By default repoman runs quietly — only its own ==> ... markers and any errors reach the terminal. Subprocess probes (e.g. incus project show, stat /nfs/repos, findmnt) have their stdout/stderr suppressed to /dev/null. The actual user-facing operations (launch, rsync) pass their stdio through.
To see the suppressed probe output for troubleshooting, run with --verbose (or -v). Pass --quiet (or -q) to force quiet mode if your config defaults to verbose.
Every invocation also writes a log file at <logdir>/<project>-<verb>.log, truncated each run. So if a repoman new veemarker fails, the log lives at ~/.local/state/repoman/veemarker-new.log until the next run with the same name+verb. Whole-tree sync uses all-sync.log.
Configuration
Central registry: ~/.config/repoman/repoman.toml (managed; do not edit while repoman is running).
Tool-level settings under [repoman]:
| Field | Values | Default | Effect |
|---|---|---|---|
output |
"quiet" | "verbose" |
"quiet" |
Default output mode (CLI flags override). |
Defaults under [defaults]:
| Field | Default | Effect |
|---|---|---|
repos_root |
~/repos |
Local NVMe canonical location. |
backup_root |
/nfs/repos |
NFS-mounted backup destination. |
logdir |
~/.local/state/repoman |
Per-invocation log files written here. |
incus_project |
repoman |
Incus project containers are created in. |
default_image |
images:ubuntu/26.04/cloud |
Image used when no --image flag and no override. |
profiles |
["default", "claude-share"] |
Profiles applied when creating containers. |
Per-project overrides: ~/.config/repoman/repos.d/<container-name>.toml (user-authored). Example:
[container]
image = "images:debian/12/cloud"
profiles = ["default", "claude-share", "node-dev"]
[[mount]]
source = "~/.npm"
path = "/home/ctusa/.npm"
[env]
NODE_ENV = "development"
Recommended Incus profile: claude-share
For the agent-friendly setup repoman is built around, create a shared profile that exposes the user's Claude state:
# (one-time)
incus profile create claude-share
incus profile edit claude-share # add your bind-mounts for ~/.claude, etc.
repoman uses profiles default and claude-share by default; override per-project in repos.d/<name>.toml.