Files
flow/README.md
2026-02-25 15:32:23 +02:00

4.8 KiB

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

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:

_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:

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)

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:

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

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 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

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
python3 -m pytest