2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00
2026-02-12 09:42:59 +02:00

flow

flow is a CLI for managing development instances, containers, dotfiles, bootstrap profiles, and binary packages.

This repository contains the Python implementation of the tool and its command modules.

What is implemented

  • Instance access via flow enter
  • Container lifecycle commands under flow dev (create, exec, connect, list, stop, remove, respawn)
  • Dotfiles management (dotfiles / dot)
  • Bootstrap planning and execution (bootstrap / setup / provision)
  • Binary package installation from manifest definitions (package / pkg)
  • Multi-repo sync checks (sync)

Installation

Build and install a standalone binary (no pip install required for use):

make build
make install-local

This installs flow to ~/.local/bin/flow.

Configuration

flow uses XDG paths by default:

  • ~/.config/devflow/config
  • ~/.config/devflow/manifest.yaml
  • ~/.local/share/devflow/
  • ~/.local/state/devflow/

config (INI)

[repository]
dotfiles_url = git@github.com:you/dotfiles.git
dotfiles_branch = main

[paths]
projects_dir = ~/projects

[defaults]
container_registry = registry.tomastm.com
container_tag = latest
tmux_session = default

[targets]
# Format A: namespace = platform ssh_host [ssh_identity]
personal = orb personal.orb

# Format B: namespace@platform = ssh_host [ssh_identity]
work@ec2 = work.internal ~/.ssh/id_work

Manifest format

The manifest is YAML with two top-level sections used by the current code:

  • profiles for bootstrap profiles
  • binaries for package definitions

environments is no longer supported.

Example:

profiles:
    linux-vm:
        os: linux
        hostname: "$HOSTNAME"
        shell: zsh
        locale: en_US.UTF-8
        requires: [HOSTNAME]
        packages:
            standard: [git, tmux, zsh]
            binary: [neovim]
        ssh_keygen:
            - type: ed25519
              comment: "$USER@$HOSTNAME"
        runcmd:
            - mkdir -p ~/projects

binaries:
    neovim:
        source: github:neovim/neovim
        version: "0.10.4"
        asset-pattern: "nvim-{{os}}-{{arch}}.tar.gz"
        platform-map:
            linux-amd64: { os: linux, arch: x86_64 }
            linux-arm64: { os: linux, arch: arm64 }
            macos-arm64: { os: macos, arch: arm64 }
        install-script: |
            curl -fL "{{downloadUrl}}" -o /tmp/nvim.tar.gz
            tar -xzf /tmp/nvim.tar.gz -C /tmp
            rm -rf ~/.local/bin/nvim
            cp /tmp/nvim-*/bin/nvim ~/.local/bin/nvim

Command overview

Enter instances

flow enter personal@orb
flow enter root@personal@orb
flow enter personal@orb --dry-run

Containers

flow dev create api -i tm0/node -p ~/projects/api
flow dev connect api
flow dev exec api -- npm test
flow dev list
flow dev stop api
flow dev remove api

Dotfiles

flow dotfiles init --repo git@github.com:you/dotfiles.git
flow dotfiles link
flow dotfiles status
flow dotfiles relink
flow dotfiles clean --dry-run

Bootstrap

flow bootstrap list
flow bootstrap show linux-vm
flow bootstrap run --profile linux-vm --var HOSTNAME=devbox
flow bootstrap run --profile linux-vm --dry-run

Packages

flow package install neovim
flow package list
flow package list --all
flow package remove neovim

Sync

flow sync check
flow sync check --no-fetch
flow sync fetch
flow sync summary

Completion

flow completion install-zsh
flow completion zsh

Self-hosted config priority

When present, flow prefers config from a linked dotfiles package:

  1. ~/.local/share/devflow/dotfiles/flow/.config/flow/config
  2. ~/.config/devflow/config

And for manifest:

  1. ~/.local/share/devflow/dotfiles/flow/.config/flow/manifest.yaml
  2. ~/.config/devflow/manifest.yaml

Passing an explicit file path to internal loaders bypasses this cascade.

State format policy

flow currently supports only the v2 dotfiles link state format (linked.json). Older state formats are intentionally not supported.

CLI behavior

  • User errors return non-zero exit codes.
  • External command failures are surfaced as concise one-line errors (no traceback spam).
  • Ctrl+C exits with code 130.

Zsh completion

Recommended one-shot install:

flow completion install-zsh

Manual install (equivalent):

mkdir -p ~/.zsh/completions
flow completion zsh > ~/.zsh/completions/_flow

Then ensure your .zshrc includes:

fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit

Completion is dynamic and pulls values from your current config/manifest/state (for example bootstrap profiles, package names, dotfiles packages, and configured enter targets).

Development

Binary build (maintainers):

python3 -m pip install pyinstaller
make build
make install-local

Useful targets:

make clean

Run a syntax check:

python3 -m compileall .

Run tests (when pytest is available):

python3 -m pytest

Optional local venv setup:

python3 -m venv .venv
.venv/bin/pip install -U pip pytest pyyaml
PYTHONPATH=/path/to/src .venv/bin/pytest
Description
No description provided
Readme 329 KiB
Languages
Python 99%
Makefile 0.9%