# flow Action-centered CLI for managing a development machine: dotfiles, packages, setup profiles, dev containers, remote targets, project git status, and shell completion. ## Quick Start From the repository: ```bash uv sync --locked --extra dev --extra build uv run flow --help uv run flow --version ``` Initialize a dotfiles repo, link a profile, and preview setup: ```bash flow dotfiles init --repo git@github.com:you/dotfiles.git flow dotfiles link --profile linux-work --dry-run flow setup show linux-work flow setup run linux-work --dry-run ``` Install the CLI as a local uv tool: ```bash uv tool install --force . flow --help ``` Build a standalone binary: ```bash make build ./dist/flow --help make install # installs dist/flow to ~/.local/bin/flow ``` `build/`, `dist/`, and `flow.spec` are generated by packaging/binary builds and are ignored. `.venv/` is the uv-managed local environment. `venv/` is legacy local clutter and should not be used. ## Command Surface ```bash # Dotfiles flow dotfiles init [--repo URL] flow dotfiles link [--profile NAME] [--dry-run] [--skip PKG...] flow dotfiles unlink [PACKAGES...] [--dry-run] flow dotfiles status [PACKAGES...] flow dotfiles edit PACKAGE [--no-commit] # Dotfiles and module repos flow dotfiles repos list flow dotfiles repos status [--repo NAME] flow dotfiles repos pull [--repo NAME] [--dry-run] flow dotfiles repos push [--repo NAME] [--dry-run] # Packages flow packages install [NAMES...] [--profile NAME] [--dry-run] flow packages remove NAMES... [--dry-run] flow packages list [--all] # Setup/bootstrap flow setup list flow setup show PROFILE flow setup run [PROFILE|--profile NAME] [--dry-run] [--var KEY=VALUE] # Remote targets flow remote list flow remote enter TARGET [--user USER] [--namespace NAME] [--platform NAME] [--session NAME] [--no-tmux] [--dry-run] flow enter TARGET # Dev containers flow dev create NAME --image IMAGE [--project PATH] [--dry-run] flow dev attach NAME flow dev exec NAME [CMD...] flow dev enter NAME flow dev stop NAME [--kill] flow dev remove NAME [--force] flow dev respawn NAME flow dev list # Projects flow projects check [--fetch] flow projects fetch flow projects summary flow sync # Shell completion flow completion zsh flow completion install-zsh [--dir DIR] [--rc FILE] [--no-rc] # Global flags flow --version flow --quiet flow --no-color ``` Aliases: - `dotfiles` -> `dot` - `dotfiles repos` -> `dotfiles repo` - `packages` -> `package`, `pkg` - `projects` -> `project`; `flow sync` -> `flow projects check --fetch` - `setup` -> `bootstrap`, `provision` - `remote enter` -> `enter` - `dev attach` -> `dev connect` - `dev remove` -> `dev rm` ## Configuration Flow reads XDG paths: - config: `~/.config/flow` - data: `~/.local/share/flow` - state: `~/.local/state/flow` The main config lives at `~/.config/flow/config.yaml`. A dotfiles repo may also provide an overlay at `_shared/flow/.config/flow/`; after `dotfiles init`, that overlay is merged into config and manifest loading. ```yaml repository: url: git@github.com:you/dotfiles.git branch: main pull-before-edit: true paths: projects: ~/projects defaults: container-runtime: auto # auto | docker | podman | podman-rootful container-registry: registry.example.com container-tag: latest tmux-session: default targets: personal@orb: personal.orb work@ec2: host: work.internal identity: ~/.ssh/id_work ``` Packages and setup profiles are YAML manifest data loaded from the same config directories: ```yaml packages: - name: fd type: pkg sources: apt: fd-find brew: fd - name: neovim type: binary source: github:neovim/neovim version: "0.10.4" platform-map: linux-x64: nvim-linux-x86_64.tar.gz install: bin: [bin/nvim] profiles: linux-work: os: linux shell: zsh packages: - fd - binary/neovim runcmd: - mkdir -p ~/projects ``` See `example/README.md` for a complete runnable dotfiles/setup fixture. ## Dotfiles Layout ```text _shared/ zsh/ .zshrc nvim/ .config/nvim/ _module.yaml system/ _root/ etc/hostname linux-work/ i3/ .config/i3/config ``` `_shared/` applies to every profile. Profile directories add or override package sets. `_root/` marks absolute paths and plans sudo-backed link actions. External module repos are declared with `_module.yaml`: ```yaml source: github:org/nvim-config ref: branch: main ``` Modules are regular git clones managed by flow, not git submodules. The dotfiles repo and all module repos are operated through `flow dotfiles repos`. ## Architecture Flow uses a single execution boundary: ```text cli -> app -> domain -> actions -> adapters ``` - `src/flow/cli.py`: Typer command definitions and argument parsing only. - `src/flow/app/`: use-cases that load config/state and build action plans. - `src/flow/domain/`: pure dataclasses, parsers, resolvers, and planners. - `src/flow/actions/`: `ActionPlan`, domain-to-primitive expansion, execution, dry-run rendering, JSONL audit logs, and rollback. - `src/flow/adapters/`: filesystem, process, git, package-manager, download, archive, container, and tmux adapters. Use-cases do not directly mutate files or run shell commands for non-interactive work. They produce actions and pass them to `ActionExecutor`. Interactive handoffs such as attaching to tmux remain explicit boundaries. Action audit records are append-only JSONL files under the relevant state directory, normally `~/.local/state/flow/actions.jsonl`. ## Development ```bash make deps # uv sync --locked --extra build --extra dev make test # unit tests, excluding e2e make test-e2e # requires Docker or healthy Podman make check # tests plus CLI smoke checks make package # wheel and sdist in dist/ make build # PyInstaller binary in dist/flow make clean # remove build/test artifacts make distclean # also remove .venv/ and venv/ ``` Direct commands are equivalent: ```bash uv run pytest tests/ -q --ignore=tests/e2e FLOW_RUN_E2E=1 uv run pytest tests/e2e/ -v uv build uv run pyinstaller --noconfirm --clean --onefile --name flow --paths src src/flow/__main__.py ```