|
root / README.md
README.md markdown 172 lines 7.9 KB

repoman

A safety harness for AI-assisted development. Per-project Incus containers + opinionated NFS backup. Current version: v0.4.4.

repoman runs each of your projects inside its own Incus (LXC) container with the repo bind-mounted in, so AI coding agents can work with broad permissions inside the container while your host OS, your other projects, and the source repo on disk stay protected. See BLURB.md for the marketing pitch and VISION.md for the design rationale.

Why

AI coding agents are productive and prone to "fixing" things you didn't ask them to touch. repoman makes the blast radius of any mistake equal to one container:

  • Host OS sealed off — the agent can mangle the container's filesystem; the host's /etc, /usr, kernel modules, and services are out of reach.
  • Projects isolated from each other — each project is its own container; an agent in project A cannot see project B.
  • Source code preserved — your repo lives on the host (~/repos/<name>) and is exposed to the container via a uid-shifted bind mount. repoman remove deletes the container, never the repo. repoman sync mirrors all repos to NFS for belt-and-suspenders recovery.
  • Authenticated agent state shared safely — vendor profiles let you bind-mount things like ~/.claude into every container so you don't re-authenticate per project, without exposing SSH keys or shell config.

Build

reefc build

Produces ./build/repoman.

Test

make test

Or per-suite:

for t in tests/test_*.reef; do
    echo "== $t =="
    reefc run "$t" || exit 1
done

Install

make
sudo make install        # installs to /usr/local/bin/repoman
                         # vendor profiles to /usr/local/share/repoman/profiles/

Quickstart

repoman setup                       # one-time host bootstrap (idempotent)
repoman profile install --all       # install vendor profiles
repoman new my-project              # bind ~/repos/my-project into a new container
repoman shell my-project            # drop into it
repoman sync                        # rsync all repos to NFS
repoman remove my-project           # destroy container; repo on host is untouched

Subcommands

Subcommand Description
setup [--non-interactive] First-time host bootstrap: create Incus project repoman, detect host LAN IP, write initial registry. Idempotent.
profile {list,install,diff,remove,show} Manage Incus profiles from the vendor library (/usr/local/share/repoman/profiles/) and user overrides (~/.config/repoman/profiles.d/).
new <name> [--repo <dirname>] [--image <image>] Launch a container in the repoman Incus project and bind-mount ~/repos/<dirname> with shift=true. Validates profiles are installed before creating.
list Print a table of all registered projects (read-only).
status [name] Show project state from registry + live incus query.
shell <name> [--cwd <path>] Open a bash login shell inside the project's container, in the repo's directory by default.
sync [name] [--no-delete] [--dry-run] Mirror local repos to NFS backup via rsync. NFS auto-mount aware.
`remove [--yes -y] [--keep-incus]`
--help / -h / help Show usage and subcommand list.
--version / -V Print version string.

Profile library

repoman ships a vendor profile library at /usr/local/share/repoman/profiles/:

  • claude-share — bind ~/.claude and ~/.local/bin/claude so containers share the host's Claude CLI auth, history, and plugins. One claude login covers every project.
  • llm-share — bind /usr/local/bin/ollama and ~/.ollama, set OLLAMA_HOST=http://<host-lan-ip>:11434 so containers reach the host's ollama daemon over LAN.
  • dotfiles — bind ~/.gitconfig and ~/.hgrc (extend with your own).

Manage with 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, drop a copy into 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.

Output and logging

By default repoman runs quietly — only its ==> ... markers and any errors reach the terminal. Subprocess probes (e.g. incus project show, findmnt) have their output suppressed. The actual user-facing operations (container launch, rsync) pass their stdio through.

Run with --verbose (-v) to see suppressed probe output for troubleshooting. Pass --quiet (-q) to force quiet if your config defaults to verbose.

Every invocation writes a log file at <logdir>/<project>-<verb>.log, truncated each run. So if 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).

Host facts under [host] (schema 3, added in v0.4):

Field Default Effect
lan_ip (auto-detected from br0) Substituted into profiles as ${HOST_LAN_IP} — used by llm-share to point containers at the host's ollama daemon.

Defaults under [defaults]:

Field Default Effect
repos_root ~/repos Local NVMe canonical location for working copies.
backup_root /nfs/repos NFS-mounted backup destination.
logdir ~/.local/state/repoman Per-invocation log files.
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:

[container]
image    = "images:debian/12/cloud"
profiles = ["default", "claude-share", "node-dev"]

[[mount]]
source = "~/.npm"
path   = "/home/ctusa/.npm"

[env]
NODE_ENV = "development"

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. The migration is automatic and lossless for the one fact that's still useful.

The --hermes / --no-hermes / --purge-hermes flags were reverted in v0.3 before tagging — they never shipped. Agents that need per-container installs (hermes and similar) are the user's responsibility: repoman shell <name> and run the installer yourself.

Smoke test (requires Incus + NFS)

# In an existing repo dir under ~/repos:
repoman new test-foo
repoman sync test-foo --dry-run
repoman remove test-foo

License

Common Development and Distribution License (CDDL) Version 1.0. (C)opyright 2026, Leafscale, LLC. See the LICENSE file for full terms.