256 lines
6.1 KiB
Markdown
256 lines
6.1 KiB
Markdown
# 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
|
|
```
|