docs+headers: AI-isolation framing in README/VISION, add BLURB and Leafscale (C) headers across all reef sources
Author:
Chris Tusa <chris.tusa@leafscale.com>
Date:
May 11, 2026 16:01
Node:
4d8a15425ff24b1eeac11473f0033a96d93f2dd5
Branch:
default
Changed files:
A
BLURB.md
Diff
diff -r e9c500d6e07e -r 4d8a15425ff2 BLURB.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BLURB.md Mon May 11 16:01:10 2026 -0500 @@ -0,0 +1,36 @@ +# repoman + +**A safety harness for AI-assisted development. Per-project Incus containers, opinionated NFS backup.** + +AI coding agents — Claude Code, Aider, Cline, Continue, Gemini CLI — are extraordinarily productive when you give them broad permissions. They are also extraordinarily good at "fixing" things you didn't ask them to touch: rewriting the wrong file, mass-editing the wrong directory, running an install script against the host, deleting a path they misread, pushing a stray commit before you can stop them. + +`repoman` puts each project inside its own [Incus](https://linuxcontainers.org/incus/) (LXC) container — a full Linux environment with its own root filesystem, package manager, and PATH — and bind-mounts just the repo's working directory into it. The agent gets a real shell that feels like its own VPS. **The host doesn't.** + +## What that buys you + +- **Your host OS stays sealed.** The agent can `apt install` whatever it wants, mangle its `/etc`, scribble into `/usr`, install systemd units — none of it reaches the host kernel, host services, or other projects. Reset is one command: `repoman remove && repoman new`. + +- **One repo, one blast zone.** Every project gets its own container in the `repoman` Incus namespace. An agent loose in project A cannot see project B. No accidental cross-edits, no shared `node_modules` corruption, no rogue file watchers. + +- **Source code survives mistakes.** Your repo lives on the host at `~/repos/<name>`; the container sees it through a uid-shifted bind mount. `repoman remove` deletes the container — **never the repo**. And `repoman sync` mirrors all your repos to NFS, so if the agent does mangle the working tree, last night's copy is still on the file server. Run that NFS on ZFS and snapshots give you full scroll-back. + +- **`--dangerously-skip-permissions` stops being dangerous.** That's the whole point: run agents with the gloves off, knowing the worst case is "throw away the container." + +- **Agents share what should be shared, nothing else.** A vendor profile library can bind-mount things like `~/.claude` (auth + history + plugins) into every container — one login, every project — without dragging in your SSH keys, browser cookies, or shell config. + +## What it is, technically + +- A single static binary (`repoman`) compiled from [reef-lang](https://reef-lang.org). No runtime to install, no Python, no Node. +- Built on **Incus**, the LXC fork that runs containers as proper Linux hosts (not application sandboxes like Docker). Real init, real services, real package managers. +- Linux-only, single-user, homelab-shaped. Niche by design. + +## A minute of it + +```bash +repoman setup # one-time host bootstrap +repoman profile install --all # install vendor profiles (claude-share, llm-share, dotfiles) +repoman new my-project # create container + bind-mount ~/repos/my-project +repoman shell my-project # drop into it; let the agent off the leash +repoman sync # rsync every repo to NFS for backup +repoman remove my-project # toss the container; the repo on host is untouched +``` diff -r e9c500d6e07e -r 4d8a15425ff2 README.md --- a/README.md Mon May 11 15:52:18 2026 -0500 +++ b/README.md Mon May 11 16:01:10 2026 -0500 @@ -1,6 +1,17 @@ # repoman -Per-project Incus containers + opinionated NFS/ZFS backup. v0.1. +**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](https://linuxcontainers.org/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](BLURB.md) for the marketing pitch and [VISION.md](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 @@ -13,6 +24,12 @@ ## Test ```bash +make test +``` + +Or per-suite: + +```bash for t in tests/test_*.reef; do echo "== $t ==" reefc run "$t" || exit 1 @@ -21,115 +38,80 @@ ## Install -System-wide via Makefile (uses `reefc build` under the hood): - ```bash make sudo make install # installs to /usr/local/bin/repoman + # vendor profiles to /usr/local/share/repoman/profiles/ ``` ## Quickstart ```bash -# First run creates ~/.config/repoman/repoman.toml with sane defaults. -repoman --help -repoman new isurus --repo isurus-project -repoman sync --dry-run -repoman list +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 | |---|---| -| `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. | +| `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. | -| `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). | +| `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 <name> [--yes | -y] [--keep-incus]` | Delete the incus container and registry entry. Prompts for confirmation unless `--yes`. The source repo on host is **never** deleted. | | `--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: +`repoman` ships a vendor profile library at `/usr/local/share/repoman/profiles/`: -- **`claude-share`** — bind `~/.claude` and `~/.local/bin/claude` into containers - so they share the host's Claude CLI auth, history, and plugins. -- **`llm-share`** — bind `/usr/local/bin/ollama` and `~/.ollama` into containers, - set `OLLAMA_HOST=http://<host-lan-ip>:11434` so containers reach the host's - ollama daemon over LAN. +- **`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 profiles via `repoman profile`: +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) +```bash +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) +To override a vendor profile, drop a copy into your user dir and edit: ```bash -# In an existing repo dir under ~/repos: -repoman new test-foo -repoman sync test-foo --dry-run -incus delete --project repoman test-foo +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 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. +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. -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. +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 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`. +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). +Central registry: `~/.config/repoman/repoman.toml` (managed; do not edit while `repoman` is running). Tool-level settings under `[repoman]`: @@ -137,19 +119,24 @@ |---|---|---|---| | `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. | +| `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 written here. | +| `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` (user-authored). Example: +Per-project overrides: `~/.config/repoman/repos.d/<container-name>.toml`: ```toml [container] @@ -164,14 +151,21 @@ NODE_ENV = "development" ``` -## Recommended Incus profile: `claude-share` +## 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. -For the agent-friendly setup repoman is built around, create a shared profile that exposes the user's Claude state: +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) ```bash -# (one-time) -incus profile create claude-share -incus profile edit claude-share # add your bind-mounts for ~/.claude, etc. +# In an existing repo dir under ~/repos: +repoman new test-foo +repoman sync test-foo --dry-run +repoman remove test-foo ``` -repoman uses profiles `default` and `claude-share` by default; override per-project in `repos.d/<name>.toml`. +## License + +MIT. diff -r e9c500d6e07e -r 4d8a15425ff2 SRCHEADER.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SRCHEADER.txt Mon May 11 16:01:10 2026 -0500 @@ -0,0 +1,17 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: ${project} + Filename: ${file.name} + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: ${file.description} + +******************************************************************************/ + diff -r e9c500d6e07e -r 4d8a15425ff2 VISION.md --- a/VISION.md Mon May 11 15:52:18 2026 -0500 +++ b/VISION.md Mon May 11 16:01:10 2026 -0500 @@ -1,95 +1,133 @@ # repoman — Vision Doc -**Status:** v0.1 design draft -**Date:** 2026-04-29 -**Origin:** Bash prototype at `~/.local/bin/repoman` (~200 LOC). This doc captures the design intent for a real productized rewrite in **reef-lang**. +**Status:** v0.4.4 shipped 2026-05-11 +**Origin:** Bash prototype at `~/.local/bin/repoman` (~200 LOC), April 2026. Productized rewrite in **reef-lang** began v0.1 (2026-04-29); current release is v0.4.4. --- ## Vision sentence -`repoman` is the bridge between a developer's local NVMe working copies, their per-project isolated Incus containers, and their homelab NFS/ZFS backup — one tool, opinionated conventions, both interactive and flag-driven. +`repoman` is a safety harness for AI-assisted development: it isolates each project inside its own Incus (LXC) container, bind-mounts the repo into it, and mirrors everything to NFS — so AI coding agents can work with broad permissions inside the container while the host OS, sibling projects, and the source repository on disk stay protected. ## Why this exists -The original problem: enable running Claude Code (or any agent / risky tool) with `--dangerously-skip-permissions` while limiting blast radius. Each project lives in its own Incus container; the host stays safe because the worst case is "lose a container, not the host." +AI coding agents — Claude Code, Aider, Cline, Continue, Gemini CLI, and the wave of others — are dramatically more productive when granted broad permissions. They are also dramatically more capable of "fixing" things you did not ask them to touch: editing the wrong file tree, running install scripts against the host, mass-replacing across a repo, deleting paths they misread, pushing stray commits. + +The original problem (which seeded the bash prototype): run Claude Code with `--dangerously-skip-permissions` without taking the host down with it. The solution: **per-project Incus containers + bind-mounted repos + NFS backup + ZFS snapshots on the file server**. Doing it manually with raw `incus` and `rsync` works but accretes ad-hoc shell scripts. `repoman` makes the workflow first-class and turns the safety properties into invariants of the tool, not habits of the operator. + +### What "safety harness" actually means -That naturally turned into a workflow: **per-project containers + bind-mounted repos + NFS backup + ZFS snapshots for history**. Doing it with raw `incus` and `rsync` works but accretes ad-hoc shell scripts. `repoman` makes the workflow first-class. +1. **Host OS sealed off.** Containers run with their own root filesystem, init, package manager, services. An agent can `apt install`, mangle `/etc`, scribble into `/usr`, install systemd units — none of it crosses the boundary. Worst case is "throw away the container." +2. **Projects isolated from each other.** Every project gets its own container in the `repoman` Incus project namespace. An agent in container A cannot read or write container B's files. No accidental cross-edits between sibling repos, no shared `node_modules` corruption, no rogue file watchers. +3. **Source code preserved.** The repo lives on the host at `~/repos/<name>` and is exposed to the container via a uid-shifted bind mount (`shift=true`, since v0.4.2). `repoman remove` deletes the container — **never the repo**. The confirmation prompt spells out exactly what gets removed (v0.4.3). +4. **Backup as recoverability.** `repoman sync` rsyncs every repo to NFS. Run that NFS on ZFS and snapshots give you point-in-time history. If an agent does mangle the working tree, you have last night's copy. +5. **Authenticated agent state shared safely.** The vendor profile library lets you bind-mount things like `~/.claude` (auth + history + plugins) into every container — one login, every project — without exposing SSH keys, browser cookies, or shell config. ## Audience Homelab developer running: -- **Incus** for containerization (Linux-only for v0.1). -- **Local SSD/NVMe** for active project working copies (latency matters). +- **Incus** for containerization (Linux-only). +- **Local SSD/NVMe** for active project working copies (latency matters for the agent's iteration loop). - **NFS-mounted remote storage** for durable backup (ideally ZFS-backed, for snapshot history). -- One developer, multiple projects. Not multi-user, not multi-host coordination. +- **One or more AI coding agents** (Claude Code, etc.) that they want to grant generous permissions to. + +One developer, multiple projects. Not multi-user, not multi-host coordination. Realistic audience size: small. Niche tool serving its narrow audience well > generic tool nobody loves. +## Mission (re-anchored in v0.4) + +`repoman` has exactly four jobs: + +1. **Provision** per-project Incus containers that bind-mount the user's git/hg repos (`repoman new`). +2. **Backup** repos to NFS via rsync (`repoman sync`). +3. **Share** host-side resources (configs, agents, runtimes) into containers via Incus profiles (`repoman profile`). +4. **Operate** the above with quality-of-life subcommands (`list`, `status`, `remove`, `shell`, `setup`). + +**What `repoman` is NOT:** +- A host-configuration tool. It does not install or configure host services (ollama, hermes, kernel modules). +- A container-image builder. It uses upstream Incus images; image curation is somebody else's tool's job. +- An arbitrary install-script runner inside containers. Per-container provisioning is the user's shell script in their project repo. + +The v0.3 attempt to bind-mount hermes from the host failed because hermes pins to a uv-vendored host-only Python. The v0.4 brainstorm explored image management to fix that, then rejected it as ongoing maintenance overhead. The conclusion: **agents fall into two categories** — bind-mountable (claude works) and non-shareable (hermes needs per-container install). `repoman` does the bind-mountable case via profiles; the rest is shell-script territory in the user's project repo. + ## Differentiators (vs rolling your own scripts) -1. **Incus `project` for ownership.** All repoman-managed containers live in an `incus project create repoman` namespace — clean scoping, no leakage into user's other Incus work, easy to nuke the entire estate. -2. **Single tool covering container lifecycle + project conventions + backup.** Existing tools each cover one slice (`incus` for containers, `restic`/`borg` for backup, `distrobox` for dev shells); none do all three with conventions tuned for "code projects on NFS/ZFS homelab." +1. **Incus `project` for ownership.** All `repoman`-managed containers live in the `incus project create repoman` namespace — clean scoping, no leakage into the user's other Incus work, easy to nuke the entire estate. +2. **Single tool covering container lifecycle + project conventions + backup + profile management.** Existing tools each cover one slice (`incus` for containers, `restic`/`borg` for backup, `distrobox` for dev shells); none do all four with conventions tuned for "AI-agent-in-a-Linux-VPS on a homelab." 3. **Opinionated backup story.** rsync mirror + autofs-aware mount checks + ZFS snapshots assumed on the file server. No bespoke history layer — ZFS is the time machine. -4. **Both interactive and flag-driven.** Same code path serves a guided wizard and a shell-scriptable CLI. -5. **Native single-binary distribution** via reef compiling to native code. No runtime install for users. +4. **Profile library with vendor/user split.** Shareable host-side things (auth state, runtime binaries, dotfiles) are first-class via Incus profiles. Vendor ships sensible defaults; user shadows them in `~/.config/repoman/profiles.d/`. `${HOST_LAN_IP}`, `${USER}`, `${HOME}` substituted at install time. +5. **Both interactive and flag-driven.** Same code path serves a guided wizard and a shell-scriptable CLI. +6. **Native single-binary distribution** via reef compiling to native code. No runtime install for users. -## v0.1 subcommands - -Every subcommand has both an interactive form (when args missing) and a flag-driven form (when args provided). Identical underlying code path. +## Subcommands as shipped (v0.4.4) | Subcommand | Purpose | |---|---| -| `repoman setup` | First-time host setup. Creates Incus project `repoman`, detects host LAN IP, writes initial registry. Idempotent. **Shipped in v0.3, trimmed in v0.4 (no longer touches profiles or LLM stack).** | -| `repoman profile {list, install, diff, remove, show}` | Manage Incus profiles from the vendor library at `/usr/local/share/repoman/profiles/` and the user override dir at `~/.config/repoman/profiles.d/`. **Shipped in v0.4.** | -| `repoman new <name> [--repo <dir>] [--image <img>]` | Create a new managed container. Bind-mounts the repo, applies profiles, restarts. Interactive form prompts for unset values. | -| `repoman list` | List managed containers: name, state, IP, repo path, image, last sync. Reads from registry + reconciles against `incus list --project repoman`. | -| `repoman shell <name>` | Drop into the container as the local user, in the repo's directory. Replaces the verbose `incus shell --user 1000 --cwd ...` invocation. | +| `repoman setup [--non-interactive]` | First-time host bootstrap. Creates Incus project `repoman`, detects host LAN IP, writes initial registry, ensures `~/.config/repoman/profiles.d/` exists. Idempotent. | +| `repoman profile {list,install,diff,remove,show}` | Manage Incus profiles from `/usr/local/share/repoman/profiles/` (vendor) and `~/.config/repoman/profiles.d/` (user shadow). Renders `${HOST_LAN_IP}` / `${USER}` / `${HOME}` at install time. | +| `repoman new <name> [--repo <dirname>] [--image <img>]` | Create a managed container. Pre-validates profiles are installed, bind-mounts the repo with `shift=true`, applies profiles, restarts. Interactive form prompts for unset values. | +| `repoman list` | Print a table of managed containers: name, repo path, image, created, last sync, backup flag. Reads from registry. | +| `repoman shell <name> [--cwd <path>]` | Drop into the container as the local user, in the repo's directory. Replaces the verbose `incus shell --user 1000 --cwd ...` invocation. | | `repoman sync [name] [--no-delete] [--dry-run]` | rsync mirror local → NFS, all projects or one. NFS auto-mount aware. ZFS snapshots on the file server provide history. | -| `repoman remove <name> [--keep-repo]` | Destroy the container; repo dir untouched by default. | -| `repoman status [name]` | Health check: container state, mounts, NFS reachability, last sync, drift between registry and Incus. | +| `repoman remove <name> [--yes \| -y] [--keep-incus]` | Destroy the container; the repo on host is never touched. Prompts for confirmation by default; `--yes` skips the prompt. | +| `repoman status [name]` | Health check: container state, mounts, NFS reachability, last sync. | + +## Out of scope -**Out of scope for v0.1:** -- Other container runtimes (Docker, Podman) — Incus only. -- Other backup destinations (S3, restic, borg) — NFS only. -- macOS/Windows — Linux only. -- Multi-host coordination, replication. -- ZFS snapshot management (file-server-side; user runs sanoid themselves). -- Cron installation (provide a doc snippet, not a subcommand). -- IDE integration. +Brainstormed and rejected during the v0.4 design conversation (see [memory: project_repoman.md](#) for full rationale): + +- **Other container runtimes** (Docker, Podman). Incus only — we depend on its full-Linux-VPS shape. +- **Other backup destinations** (S3, restic, borg). NFS only. +- **macOS/Windows.** Linux only. +- **Multi-host coordination, replication.** +- **ZFS snapshot management** (file-server-side; user runs sanoid/syncoid themselves). +- **Cron installation** (provide a doc snippet, not a subcommand). +- **IDE integration.** +- **Image building / curation** (`repoman image build/refresh/list/prune`). Rejected: maintenance burden outweighs benefit for homelab usage volumes. +- **`[install]` block in override files** (per-project install commands run in container at create). Rejected: users put `scripts/install.sh` in their project repo and run it after `repoman shell`. Not worth a TOML schema + lifecycle + security model. +- **Setup wizard configuring host services** (ollama auto-install, systemd overrides, model pulls). Rejected: scope creep across the host-config boundary. +- **`--hermes` / per-container hermes provisioning.** Hard-rejected after v0.3 iterations failed on uv-vendored Python portability. ## Configuration -**Central registry:** `~/.config/repoman/repoman.toml` - -Tracks every project repoman owns. Source of truth for "what should exist." +**Central registry:** `~/.config/repoman/repoman.toml` (schema 3 as of v0.4) ```toml +schema = 3 + +[repoman] +output = "quiet" + +[host] +lan_ip = "192.168.1.42" + [defaults] -local_repos = "~/repos" -nfs_repos = "/nfs/repos" +repos_root = "~/repos" +backup_root = "/nfs/repos" +logdir = "~/.local/state/repoman" incus_project = "repoman" default_image = "images:ubuntu/26.04/cloud" profiles = ["default", "claude-share"] [[project]] name = "isurus" -repo = "isurus-project" # relative to local_repos +repo = "isurus-project" image = "images:ubuntu/26.04/cloud" +profiles = ["default", "claude-share"] created = "2026-04-28T15:00:00Z" last_sync = "2026-04-28T20:17:03Z" backup = true ``` -**Per-project override (optional):** `<repo>/.repoman.toml` - -Lets a repo declare its own runtime needs. Read on `new`, can be re-applied with `repoman update <name>`. +**Per-project override (optional):** `~/.config/repoman/repos.d/<name>.toml` ```toml -image = "images:debian/12/cloud" -profiles = ["default", "claude-share", "node-dev"] +[container] +image = "images:debian/12/cloud" +profiles = ["default", "claude-share", "node-dev"] -[[mount]] # extra bind-mounts beyond the repo itself +[[mount]] source = "~/.npm" path = "/home/ctusa/.npm" @@ -97,113 +135,80 @@ NODE_ENV = "development" ``` -## Drift handling - -**Source of truth:** repoman registry. **Reality:** Incus DB. - -Every command opens with a reconciliation pass against `incus list --project repoman`: - -- Container in registry but not in Incus → flag missing, offer to recreate or remove from registry. -- Container in Incus (in `repoman` project) but not in registry → flag orphan, offer to adopt or destroy. -- Differences in state — note in `list` / `status` output. - -Reconciliation is read-only by default; modifications need explicit `--repair` or interactive confirmation. - ## Implementation: reef-lang Reef has the right shape for this: - **Native compilation** → C → GCC/Clang → static binary. Single-file distribution. -- **Stdlib coverage we'll use:** - - `encoding.toml` — config files (central registry + per-project) - - `encoding.json` — Incus REST API responses - - `net.http` (with bundled LibreSSL) — talk to Incus over unix-socket REST API - - `net.unix` — raw unix-socket primitives (`unix_connect`/`unix_send`/`unix_recv`), fallback if `net.http` doesn't accept a unix-socket transport - - `sys.args` / `sys.flag` — CLI argument and flag parsing - - `sys.env` — env var reads (`LOCAL_REPOS`, `NFS_REPOS`, etc.) - - `sys.process` — argv-list `process_spawn(program, [argv])` for rsync/incus shell-outs (full POSIX surface incl. wait/kill/signal/setsid) - - `sys.signal` — graceful Ctrl-C handling during long syncs - - `io.console` — interactive prompts for the wizard mode +- **Stdlib coverage in use:** + - `encoding.toml` — central registry + per-project overrides + profile YAML helpers + - `sys.args` / `sys.flag` — CLI parsing + - `sys.env` — env var reads + - `sys.process` — argv-list `process_run` / `process_spawn` for rsync/incus shell-outs (no `process_spawn_shell`: user-derived names cannot trigger shell injection) + - `io.console` — interactive prompts (`confirm`, `confirm_default_no`) - `io.file`, `io.dir`, `io.path`, `io.stream` — local FS ops - - `fs.stat`, `fs.perm` — file metadata, permissions, uid/gid name resolution - - `core.result`, `core.option` — error handling primitives - - **Active Objects** — natural fit for parallel operations (e.g. `repoman sync` syncing N projects concurrently, or healthchecks across containers) + - `core.result_generic`, `core.option` — error handling primitives - **Multi-platform reef** = future macOS/BSD/illumos support comes for free if/when needed. +- **Currently pins reef-lang 0.5.20** (source at `~/reef-lang-0.5.20-source/`). -### Open implementation questions +### Resolved implementation questions + +- **Subprocess execution.** `sys.process` provides the POSIX surface needed. Rule: argv-list `process_run` / `process_spawn` exclusively; never `process_spawn_shell` for user-derived inputs. +- **Incus integration.** Decision: CLI shell-out (`incus` invoked with argv-list, `--format json` where useful). REST-via-unix-socket migration deferred until a concrete need arises. +- **Interactive UX.** Line-based prompts using `io.console`. Rich TUI was out of scope and stayed out. +- **uid mapping for bind mounts.** Resolved in v0.4.2: every `cmd_new` repo bind is created with `shift=true` so host uid 1000 maps to container uid 1000. + +## Versions shipped -1. **Subprocess execution.** *(Resolved — 2026-04-29)* `reef-stdlib/sys/process.reef` exports a comprehensive POSIX surface: `process_spawn(program, argv: [string])`, `process_exec(program, argv)`, `process_spawn_shell(cmd)`, `process_fork()`, plus `process_wait` / `process_try_wait` / `process_wait_any[_nohang]`, `process_kill` / `killpg`, `process_setsid` / `process_set/getpgid`, `umask`, `getpid` / `getppid`, and post-wait introspection (`process_exit_code`, `process_exited_normally`, `process_was_signaled`, `process_term_signal`). **Implementation rule for repoman:** use `process_spawn(program, argv)` exclusively for rsync and incus invocations — never `process_spawn_shell`, so user-derived names (container/repo/path) cannot cause shell injection. -2. **Incus integration: REST vs CLI shell-out.** - - **REST** (preferred long-term): unix socket `/var/lib/incus/unix.socket`, JSON in/out, structured error codes. Cleaner. Reef has raw unix-socket I/O via `net.unix`; whether `net.http` accepts a unix-socket transport directly still needs verification — if not, build a minimal HTTP-over-unix on top of `net.unix`. - - **CLI shell-out** (faster to bootstrap): parse `incus list --format json`. Brittle but works today. - - *Recommendation: shell out for v0.1 (using `process_spawn`, argv-list), migrate per-command to REST as we go.* -3. **Interactive UX library.** `io.console` provides line I/O. For richer prompts (default values, validation, menus), do we build a thin reef wrapper or keep it line-based? *Recommendation: line-based prompts in v0.1; richer UX is v0.2.* -4. **Reef stability.** Reef is at 0.5.9. Pre-1.0 means breaking changes possible. Recent reef work has been GC stability fixes (BUG-033, BUG-034 through 0.5.7) — encouraging signal. Building repoman in reef serves as a real-world stress test that *helps* the language. Coordinate with reef releases for stability windows. -5. **Project structure inside reef.** Module layout, build setup, test framework — needs a separate "scaffolding" task before feature work. +- **v0.1** (2026-04-29): `new` + `sync` subcommands, Incus `project repoman` namespace, central registry. +- **v0.2** (2026-05-05): added `list`, `status`, `remove`, `shell`. +- **v0.3** (2026-05-08): `setup` wizard, `llm-share` profile (ollama-over-LAN), schema-2 migration. `--hermes` experiment reverted before tag. +- **v0.4** (2026-05-09): `profile` subcommand family, vendor profile library with user-shadow override, schema-3 migration (drops `[defaults].llm`, adds `[host].lan_ip`), setup wizard trimmed (no more `--with-llm`). +- **v0.4.2** (2026-05-11): `cmd_new` bind-mounts with `shift=true` so host uid maps into the container — agents in containers can actually write to the repo as the in-container user. +- **v0.4.3** (2026-05-11): `cmd_remove` confirmation prompt spells out exactly what gets removed; reassures the user that the source repo on host is not touched. +- **v0.4.4** (2026-05-11): `--version` reports the actual version; build-warning cleanup. -## Migration from bash prototype +## Success criteria for v0.x -The current bash `~/.local/bin/repoman` covers `create` and `sync`. The reef rewrite should: +- [x] Builds clean from a fresh reef-lang install on Linux x86_64. +- [x] `repoman setup` runs idempotently and produces a working baseline on a fresh host. +- [x] `repoman new` creates a container, matches the bash prototype's behavior, and persists in the registry with per-project override support. +- [x] `repoman sync` matches the bash prototype's behavior with autofs check + mirror semantics. +- [x] All subcommands have both interactive and flag-driven invocation paths. +- [x] Bind mounts respect host UID/GID so containers can write to the repo. +- [x] License chosen (MIT). +- [ ] Single static binary distributable via tarball or per-distro package. +- [x] README + VISION + per-feature doc. +- [ ] Public repo on a forge with a contribution guide. -1. Match feature parity with bash version on day 1 (`new` ≈ `create`, plus `sync`). -2. Add `setup`, `list`, `shell`, `remove`, `status` as the actual productization. -3. Introduce the Incus `project` namespace (the bash version doesn't use it — all containers live in the default project). -4. Keep config-by-env-var as a fallback for the central registry's `[defaults]` section, so existing automation isn't broken. +## Open product questions -The bash script stays useful as a simpler tool while the rewrite matures. Plan for a clean cut-over once the reef version is stable, not a parallel maintenance burden. +1. **Forge.** GitHub, Codeberg, self-hosted? Distribution implications (binaries, releases). +2. **Versioning toward 1.0.** Current cadence is rapid patch releases. What's the 1.0 bar? Probably "stable schema + public forge + tarball releases." +3. **Logging / observability.** Stderr + per-invocation log files today. Structured (JSONL) output mode for automation — needed yet? +4. **Configuration migration policy.** Schema 1 → 2 → 3 worked as implicit lossless migration on parse. Same approach for the next bump? -## Naming convention (post-fix) +--- -In bash v1, the create command had implicit `-project` suffix logic that conflated container name with repo name. **v0.1 reef contract:** +## Naming convention - Container name = `<name>` (positional, required). - Repo dirname = `<name>` by default, overridable with `--repo <dirname>`. -- Repo absolute path = `<local_repos>/<repo-dirname>`. +- Repo absolute path = `<repos_root>/<repo-dirname>`. - No magic suffix logic. Explicit > implicit. ## Differentiation reality check -**Why someone would pick repoman over their own scripts:** +**Why someone would pick `repoman`:** +- They want to run AI agents with `--dangerously-skip-permissions` (or its equivalent) without taking the host down. - They want the Incus-project-as-namespace pattern but don't want to wire it themselves. -- They want guided setup — first-time onboarding into "this style of homelab dev workflow." +- They want a guided onboarding into "this style of homelab dev workflow." - They want a unified registry of "what projects do I have, where are they, when did they last back up." **Why they wouldn't:** - They already have ansible/nix/etc. covering this. - They use Docker, not Incus. - They don't separate local working copies from backup destinations. +- They run their agents under tighter constraints (microVMs, gVisor, restricted unix users) and don't need a container-shaped harness. That's fine. The audience is small and that's the intentional design. - -## Success criteria for v0.1 - -- [x] Builds clean from a fresh reef-lang install on Linux x86_64. -- [x] `repoman setup` runs idempotently and produces a working baseline on a fresh host. -- [x] `repoman new` creates a container that matches the bash prototype's behavior, then surpasses it (uses Incus project, persists in registry, supports per-project config). -- [x] `repoman sync` matches bash prototype's behavior with autofs check + mirror semantics. -- [x] All subcommands have both interactive and flag-driven invocation paths. -- [ ] Single static binary distributable via tarball or a per-distro package. -- [x] README + man page + at least one end-to-end example walkthrough. -- [ ] License chosen (MIT or Apache-2.0; user's call). -- [ ] Public repo on a forge with a clear contribution guide. - -## Open product questions - -1. **License.** MIT? Apache-2.0? Let user decide. -2. **Forge.** GitHub, Codeberg, self-hosted? Distribution implications (binaries, releases). -3. **Versioning.** Semver. v0.x while pre-1.0 (parallel with reef's own version). -4. **Configuration migration.** When `repoman.toml` schema changes between versions, how do we migrate? `repoman config migrate`? -5. **Logging / observability.** Just stderr for now, or structured (JSON lines) output mode for automation? - ---- - -## Handover note - -This doc is the contract. The bash prototype at `~/.local/bin/repoman` is the **behavioral spec** — it's running in production on this host (cron-synced nightly, shipped containers in use). Read its source to understand exactly what `new`/`sync` do today before reimplementing in reef. - -The next session should start by: - -1. Reading this doc and the bash prototype together. -2. Auditing reef-lang's stdlib for the gaps called out (notably subprocess exec). -3. Sketching the reef project skeleton (module layout, Makefile/build, first hello-world `repoman --version`). -4. Porting `sync` first (simpler, less surface area) before `new` (more moving parts). diff -r e9c500d6e07e -r 4d8a15425ff2 src/cli.reef --- a/src/cli.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/cli.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/cli.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Subcommand implementations (cmd_new, cmd_sync, cmd_list, cmd_remove, cmd_shell, cmd_status, cmd_profile) + +******************************************************************************/ + module cli import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/config.reef --- a/src/config.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/config.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/config.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Registry parse/serialize/migrate (schema 1 -> 2 -> 3) and per-project overrides + +******************************************************************************/ + module config import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/hermes.reef --- a/src/hermes.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/hermes.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/hermes.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Hermes classify/paths helpers (library only; not wired to a CLI subcommand) + +******************************************************************************/ + module hermes import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/incus.reef --- a/src/incus.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/incus.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/incus.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Wrappers over the incus CLI (launch, delete, profile ops, device add with shift) + +******************************************************************************/ + module incus import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/log.reef --- a/src/log.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/log.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/log.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Per-invocation log file writer + +******************************************************************************/ + module log import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/main.reef --- a/src/main.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/main.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/main.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Entry point — argv dispatch to subcommand handlers + +******************************************************************************/ + import cli import sys.args as args import sys.process as p diff -r e9c500d6e07e -r 4d8a15425ff2 src/paths.reef --- a/src/paths.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/paths.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/paths.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Path helpers (home expansion, registry path, log path) + +******************************************************************************/ + module paths import io.path as iopath diff -r e9c500d6e07e -r 4d8a15425ff2 src/profile.reef --- a/src/profile.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/profile.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/profile.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Profile library: vendor/user shadowing and ${HOST_LAN_IP}/${USER}/${HOME} substitution + +******************************************************************************/ + module profile import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/setup.reef --- a/src/setup.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/setup.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/setup.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: First-time host bootstrap wizard (cmd_setup) + +******************************************************************************/ + module setup import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 src/sync.reef --- a/src/sync.reef Mon May 11 15:52:18 2026 -0500 +++ b/src/sync.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: src/sync.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: rsync-to-NFS backup driver (cmd_sync) with autofs/mount awareness + +******************************************************************************/ + module sync import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_io.reef --- a/tests/test_config_io.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_io.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_io.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: registry file I/O + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_merge.reef --- a/tests/test_config_merge.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_merge.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_merge.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: project + override merge logic + +******************************************************************************/ + import config import test.framework import sys.env diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_migrate.reef --- a/tests/test_config_migrate.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_migrate.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_migrate.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: schema 1 -> 2 -> 3 migration + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_mutate.reef --- a/tests/test_config_mutate.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_mutate.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_mutate.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: registry mutation helpers + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_override.reef --- a/tests/test_config_override.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_override.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_override.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: per-project override parsing and application + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_parse.reef --- a/tests/test_config_parse.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_parse.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_parse.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: registry TOML parsing + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_roundtrip.reef --- a/tests/test_config_roundtrip.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_roundtrip.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_roundtrip.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: parse-then-serialize roundtrip + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_save.reef --- a/tests/test_config_save.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_save.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_save.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: registry save semantics + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_schema_v3.reef --- a/tests/test_config_schema_v3.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_schema_v3.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_schema_v3.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: schema 3 ([host].lan_ip) parse/serialize + +******************************************************************************/ + import config import test.framework import core.result_generic as rg diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_config_serialize.reef --- a/tests/test_config_serialize.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_config_serialize.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_config_serialize.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: registry TOML serialization + +******************************************************************************/ + import config import test.framework diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_hermes_classify.reef --- a/tests/test_hermes_classify.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_hermes_classify.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_hermes_classify.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: hermes path classification helper + +******************************************************************************/ + import hermes import test.framework diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_hermes_paths.reef --- a/tests/test_hermes_paths.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_hermes_paths.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_hermes_paths.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: hermes path resolution helper + +******************************************************************************/ + import hermes import test.framework diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_incus_validate.reef --- a/tests/test_incus_validate.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_incus_validate.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_incus_validate.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: incus container name validation + +******************************************************************************/ + import incus import test.framework import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_paths.reef --- a/tests/test_paths.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_paths.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_paths.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: path helpers + +******************************************************************************/ + import paths import test.framework import sys.env diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_profile_paths.reef --- a/tests/test_profile_paths.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_profile_paths.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_profile_paths.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: profile vendor/user dir resolution + +******************************************************************************/ + import profile import test.framework diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_profile_render.reef --- a/tests/test_profile_render.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_profile_render.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_profile_render.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: profile ${VAR} substitution at install time + +******************************************************************************/ + import profile import test.framework import core.str diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_setup_planner.reef --- a/tests/test_setup_planner.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_setup_planner.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_setup_planner.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: setup stage planner + +******************************************************************************/ + import setup import test.framework diff -r e9c500d6e07e -r 4d8a15425ff2 tests/test_sync_args.reef --- a/tests/test_sync_args.reef Mon May 11 15:52:18 2026 -0500 +++ b/tests/test_sync_args.reef Mon May 11 16:01:10 2026 -0500 @@ -1,3 +1,20 @@ +/****************************************************************************** + __ ____ __ + / / ___ ____ _/ __/_____________ _/ /__ + / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ + / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ + /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ + + (C)opyright 2026, Leafscale, LLC - https://www.leafscale.com + + Project: repoman + Filename: tests/test_sync_args.reef + Authors: Chris Tusa <chris.tusa@leafscale.com> + License: <see LICENSE file included with this source code> +Description: Tests: sync argv parsing + +******************************************************************************/ + import sync import test.framework