Files
flow/README.md
2026-02-13 12:15:46 +02:00

183 lines
4.0 KiB
Markdown

# 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.
### Dotfiles layout (flat with reserved dirs)
Inside your dotfiles repo root:
```text
_shared/
flow/
.config/flow/
config.yaml
packages.yaml
profiles.yaml
git/
.gitconfig
_root/
general/
etc/
hostname
linux-auto/
nvim/
.config/nvim/init.lua
```
- `_shared/`: linked for all profiles
- `_root/`: linked to absolute paths (via sudo), e.g. `_root/etc/hostname -> /etc/hostname`
- every other directory at this level is a profile name
- when `_shared` and profile conflict on the same target file, profile wins
## 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 + `_root`)
- `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 status
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
```