# flow `flow` is a CLI for managing development instances, containers, dotfiles, and host bootstrap. ## What is implemented - Instance access via `flow enter` - Container lifecycle under `flow dev` - Dotfiles repo management (`flow dotfiles`) - Bootstrap provisioning (`flow bootstrap`) - Package installs from unified manifest definitions (`flow package`) - Project sync checks (`flow sync`) ## Installation ```bash make build make install-local ``` This installs `flow` to `~/.local/bin/flow`. ## Core behavior ### Security model - `flow` must run as a regular user (root/sudo invocation is rejected). - At startup, `flow` refreshes sudo credentials once (`sudo -v`) for privileged steps. - Package `post-install` hooks run without sudo by default. - A package hook can use sudo only when `allow_sudo: true` is explicitly set. ### Config location and merge rules `flow` loads all YAML files from: 1. `~/.local/share/flow/dotfiles/_shared/flow/.config/flow/` (self-hosted, if present) 2. `~/.config/flow/` (local fallback) Files are read alphabetically (`*.yaml` and `*.yml`) and merged at top level. If the same top-level key appears in multiple files, the later filename wins. `repository.pull-before-edit` controls whether `flow dotfiles edit` runs `git pull --rebase` first (default: `true`). When pull brings new changes, flow shows an info message and waits for Enter before opening the editor. ### Dotfiles layout (flat with reserved dirs) Inside your dotfiles repo root: ```text _shared/ flow/ .config/flow/ config.yaml packages.yaml profiles.yaml dnsmasq/ .user_hosts _root/ opt/homebrew/etc/dnsmasq.conf git/ .gitconfig linux-auto/ nvim/ .config/nvim/init.lua ``` - `_shared/`: linked for all profiles - `_root/` is a marker inside a package for absolute paths (via sudo), e.g. `dnsmasq/_root/etc/hostname -> /etc/hostname` - every other directory at this level is a profile name - any target conflict fails (including `_shared` vs profile) ### External module packages Packages can be backed by an external git repository using `_module.yaml`: ```yaml source: github:org/nvim-config ref: branch: main ``` - If a package directory contains `_module.yaml`, flow uses the fetched module content as package source. - Any sibling files in that package directory are ignored (shown only in `--verbose`). - Modules are refreshed on `flow dotfiles init` and `flow dotfiles sync` (not on `link`). ## Manifest model Top-level keys: - `profiles` - `packages` - optional global settings like `repository`, `paths`, `defaults`, `targets` `environments` is not supported. ### Packages (unified) ```yaml packages: - name: fd type: pkg sources: apt: fd-find dnf: fd-find brew: fd - name: wezterm type: cask sources: brew: wezterm - name: neovim type: binary source: github:neovim/neovim version: "0.10.4" asset-pattern: "nvim-{{os}}-{{arch}}.tar.gz" platform-map: linux-x64: { os: linux, arch: x64 } linux-arm64: { os: linux, arch: arm64 } darwin-arm64: { os: macos, arch: arm64 } extract-dir: "nvim-{{os}}64" install: bin: [bin/nvim] share: [share/nvim] man: [share/man/man1/nvim.1] lib: [lib/libnvim.so] ``` ### Profile package syntaxes All are supported in one profile list: ```yaml profiles: macos-dev: os: macos packages: - git - cask/wezterm - binary/neovim - name: docker allow_sudo: true post-install: | sudo groupadd docker || true sudo usermod -aG docker $USER ``` ### Templates - `{{ env.VAR_NAME }}` - `{{ version }}` - `{{ os }}` - `{{ arch }}` ### Bootstrap profile features - `os` is required (`linux` or `macos`) - `package-manager` optional (auto-detected if omitted) - default locale is `en_US.UTF-8` - shell auto-install + `chsh` when `shell:` is declared and missing - `requires` validation for required env vars - `ssh-keygen` definitions - `runcmd` (runs after package installation) - automatic config linking (`_shared` + profile, including package-local `_root` markers) - `post-link` hook (runs after symlink phase) - config skip patterns: - package names (e.g. `nvim`) - `_shared` - `_profile` - `_root` ## Command overview ```bash flow enter personal@orb flow dev create api -i tm0/node -p ~/projects/api flow dotfiles init --repo git@github.com:you/dotfiles.git flow dotfiles link --profile linux-auto flow dotfiles undo flow dotfiles status flow dotfiles modules list flow dotfiles modules sync flow bootstrap list flow bootstrap show linux-auto flow bootstrap run --profile linux-auto --var USER_EMAIL=you@example.com flow package install neovim flow package list --all flow sync check flow completion install-zsh ``` ## Development ```bash python3 -m venv .venv .venv/bin/pip install -e ".[dev]" python3 -m pytest FLOW_RUN_E2E_CONTAINER=1 .venv/bin/pytest -q tests/test_dotfiles_e2e_container.py ```