Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 41 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ Working across multiple repos means repetitive setup, scattered branches, and cl

![flow demo](demo.gif)

## Motivation
## Features

Flow is designed to be called by other AI agents — tools like [OpenClaw](https://github.com/openclaw) that integrate with Slack, Linear, or other services to understand context and then programmatically create state files and initialize workspaces. Prompt OpenClaw with a Slack thread or Linear ticket and let your agent create the workspace using Flow 🌊
🌳 **Workspaces as code** — Declare repos and branches in a YAML state file. Repos are cloned once into a shared cache and checked out as lightweight git worktrees, so multiple workspaces pointing at the same repo don't duplicate data.

Agents should call deterministic tools rather than relying on freeform interpretation with skills. This leads to more consistent results and reproducible environments.
🚦 **Status tracking** — Define custom check commands that dynamically resolve the status of each repo in a workspace.

🤖 **AI agent integration** — Generate shared context files and agent instructions across repos so your AI tools have the right skills and knowledge from the start.

## Why flow?

AI agents work best when they have deterministic tools instead of freeform instructions. Asking an agent to "set up a multi-repo workspace" produces inconsistent results — but giving it a CLI that manages YAML state files, bare clone caches, and git worktrees produces the same result every time.

## Quickstart
Flow is that deterministic layer. It gives agents (and humans) a small set of reliable commands for workspace lifecycle: create, define repos in YAML, render worktrees, check status. Agents call these tools through embedded skills rather than interpreting setup instructions on their own.

Beyond workspace creation, flow centralizes agent skills across all your workspaces and lets you check the status of many workstreams in parallel. It is not opinionated about which agent or editor you use — configure Claude, Cursor, or anything else in a single config file. Everything is customizable: status checks, agent skills, workspace structure.

## Getting started

<details>
<summary><strong>Install</strong></summary>
Expand All @@ -39,53 +49,29 @@ make install

</details>

<details>
<summary><strong>Usage</strong></summary>

### 1. Create a workspace

Flow creates a workspace with an empty state file.
### Create a workspace and start working

```bash
flow init
```

### 2. Add repos

Open the state file in `$EDITOR` and define which repos and branches belong together.
Flow creates a workspace and launches your configured agent. Describe what you're working on and the agent handles the rest.

```bash
flow edit state calm-delta
flow init my-project
```

### 3. Render it

Flow fetches each repo into a shared bare clone cache, then creates lightweight worktrees in the workspace directory. Rendering is idempotent — re-running fetches updates and skips worktrees that already exist.
The agent reads its embedded skills to edit `state.yaml`, run `flow render`, and begin working in the repos.

```bash
flow render calm-delta
```

### 4. Start working
### Manual workflow

Launch your default agent directly into the workspace. Flow reads the `spec.agents` list from your global config and runs the one marked `default: true`.
Use `--no-exec` to skip the agent launch and set things up yourself:

```bash
flow exec calm-delta
flow init my-project --no-exec
flow edit state my-project # add repos and branches
flow render my-project # clone repos, create worktrees
flow exec my-project # launch agent manually
```

See the [spec reference](docs/specs/) for YAML file schemas and the [command reference](docs/commands/) for all commands.

</details>

## What it does

🌳 **Workspaces as code** — Declare git worktrees in a YAML state file for instant, reproducible workspace setup across repos and branches.

🚦 **Status tracking** — Define custom check commands that dynamically resolve the status of each repo in a workspace.

🤖 **AI agent integration** — Generate shared context files and agent instructions across repos so your AI tools have the right skills and knowledge from the start.

## How it works

Flow stores everything under `~/.flow` (override with `$FLOW_HOME`):
Expand All @@ -98,8 +84,9 @@ Flow stores everything under `~/.flow` (override with `$FLOW_HOME`):
│ └── claude/
│ ├── CLAUDE.md # Shared agent instructions
│ └── skills/
│ ├── flow-cli/SKILL.md # Flow CLI skill
│ └── workspace-structure/SKILL.md
│ ├── flow-cli/SKILL.md # Built-in: workspace management
│ ├── workspace-structure/SKILL.md # Built-in: directory layout
│ └── find-repo/SKILL.md # Your own custom skill
├── workspaces/
│ └── calm-delta/ # Workspace ID
│ ├── state.yaml # Workspace manifest (name: vpc-ipv6)
Expand All @@ -118,31 +105,27 @@ Flow stores everything under `~/.flow` (override with `$FLOW_HOME`):

Bare clones are shared across workspaces. Worktrees are cheap — they share the object store with the bare clone, so multiple workspaces pointing at the same repo don't duplicate data.

See the [spec reference](docs/specs/) for YAML file schemas and the [command reference](docs/commands/) for usage, flags, and GIF demos.
Flow ships two built-in skills (`flow-cli` and `workspace-structure`) and preserves any custom skills you add to the same directory. Run `flow reset skills` to update the built-in skills without touching your own.

## Requirements

- Go 1.25+
- Git 2.20+ (worktree support)
See the [spec reference](docs/specs/) for YAML file schemas and the [command reference](docs/commands/) for usage, flags, and GIF demos.

## Development
## Customization

```bash
git clone https://github.com/milldr/flow.git
cd flow
Flow stores everything under `~/.flow` (override with `$FLOW_HOME`). Edit these files to customize your setup:

# Build
make build
| Command | What it configures |
|---------|-------------------|
| `flow edit config` | Default agent, editor preferences |
| `flow edit status` | Status checks for tracking workstreams |
| `flow edit state <workspace>` | Repos and branches for a workspace |
| `flow reset skills` | Restore default agent skills to latest |

# Run tests
make test
See the [spec reference](docs/specs/) for YAML schemas and the [command reference](docs/commands/) for all commands.

# Lint
make lint
## Requirements

# Build release snapshot
make snapshot
```
- Go 1.25+
- Git 2.20+ (worktree support)

## Support

Expand Down
116 changes: 106 additions & 10 deletions demo-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,54 @@ FLOW="$(pwd)/flow"
rm -rf /tmp/flow-demo /tmp/demo
mkdir -p /tmp/demo "$FLOW_HOME/workspaces" "$FLOW_HOME/repos"

# --- Create a fake claude binary that simulates an interactive agent session ---

mkdir -p /tmp/flow-demo/bin
cat > /tmp/flow-demo/bin/claude <<'SCRIPT'
#!/bin/bash
DIM='\033[2m'
CYAN='\033[36m'
GREEN='\033[32m'
BOLD='\033[1m'
RESET='\033[0m'

echo ""
echo -e " ${DIM}[mocked agent session]${RESET}"
echo ""
echo -e " ${DIM}Flow includes skills that teach your agent to manage workspaces.${RESET}"
echo -e " ${DIM}Add your own skills for repo discovery, PR lookup, or any custom workflow.${RESET}"
echo -e " ${DIM}Paste a Slack thread, dictate a bug report — the agent handles the rest.${RESET}"
echo ""
echo -e " ${BOLD}Enter your prompt:${RESET}"
echo ""
printf " > "
read -r task

echo ""
sleep 0.5
echo -e " ${CYAN}● Reading skill: flow-cli${RESET}"
sleep 0.6
echo -e " ${CYAN}● Reading skill: find-repo${RESET}"
echo -e " ${DIM}→ github.com/acme/web${RESET}"
sleep 0.6
echo -e " ${CYAN}● Editing state.yaml${RESET}"
echo -e " ${DIM}name: fix-dashboard-charts${RESET}"
echo -e " ${DIM}repo: github.com/acme/web @ fix/dashboard-charts${RESET}"
sleep 0.6
echo -e " ${CYAN}● Running flow render...${RESET}"
sleep 0.8
echo ""
echo -e " ${GREEN}✓ Workspace ready${RESET}"
echo ""
echo -e " ${CYAN}● Analyzing web/src/components/Charts.tsx...${RESET}"
sleep 0.8
echo ""
printf " > "
read -r cmd
echo ""
SCRIPT
chmod +x /tmp/flow-demo/bin/claude

# --- Create local git repos with feature branches ---

create_repo() {
Expand All @@ -25,14 +73,16 @@ create_repo() {
git -C "$dir" commit -q -m "$msg"
}

create_repo "app" "feature/ipv6" "main.go" "add ipv6 support"
create_repo "api" "feat/auth" "main.go" "add auth endpoints"
create_repo "docs" "update/guides" "README.md" "update setup guide"
create_repo "web" "feat/dashboard" "main.go" "add dashboard page"
create_repo "app" "feature/ipv6" "main.go" "add ipv6 support"
create_repo "api" "feat/auth" "main.go" "add auth endpoints"
create_repo "docs" "update/guides" "README.md" "update setup guide"
create_repo "web" "feat/dashboard" "main.go" "add dashboard page"
create_repo "billing" "feat/billing-v2" "main.go" "billing v2 migration"
create_repo "gateway" "feat/rate-limits" "main.go" "add rate limiting"

# --- Pre-populate bare clone cache for realistic URLs ---

for name in app api docs web; do
for name in app api docs web billing gateway; do
bare="$FLOW_HOME/repos/github.com/acme/${name}.git"
mkdir -p "$(dirname "$bare")"
git clone --bare "/tmp/demo/$name" "$bare" -q
Expand All @@ -49,6 +99,7 @@ create_workspace() {
echo "$yaml" > "$FLOW_HOME/workspaces/$id/state.yaml"
}

# Workspace: api-refactor — will be "in-progress" (has local diffs)
create_workspace "bold-creek" "$(cat <<'YAML'
apiVersion: flow/v1
kind: State
Expand All @@ -67,6 +118,7 @@ spec:
YAML
)"

# Workspace: infra-update — will be "in-review" (marker file)
create_workspace "swift-pine" "$(cat <<'YAML'
apiVersion: flow/v1
kind: State
Expand All @@ -82,12 +134,47 @@ spec:
YAML
)"

# Render both workspaces so exec and status work
# Workspace: billing-v2 — will be "closed" (marker file)
create_workspace "calm-ridge" "$(cat <<'YAML'
apiVersion: flow/v1
kind: State
metadata:
name: billing-v2
description: Migrate billing system to v2
created: "2026-02-15T10:00:00Z"
spec:
repos:
- url: github.com/acme/billing
branch: feat/billing-v2
path: billing
YAML
)"

# Workspace: rate-limits — will be "in-progress" (has local diffs)
create_workspace "dry-fog" "$(cat <<'YAML'
apiVersion: flow/v1
kind: State
metadata:
name: rate-limits
description: Add rate limiting to API gateway
created: "2026-02-23T16:00:00Z"
spec:
repos:
- url: github.com/acme/gateway
branch: feat/rate-limits
path: gateway
YAML
)"

# Render all workspaces
$FLOW render bold-creek
$FLOW render swift-pine
$FLOW render calm-ridge
$FLOW render dry-fog

# --- Add local commits so status checks detect diffs ---
# --- Set up different statuses via local changes and marker files ---

# api-refactor: "in-progress" — add local commits so git diff detects changes
add_local_change() {
local ws_dir="$FLOW_HOME/workspaces/$1/$2"
git -C "$ws_dir" fetch -q origin 2>/dev/null || true
Expand All @@ -98,25 +185,34 @@ add_local_change() {

add_local_change "bold-creek" "api"
add_local_change "bold-creek" "docs"
add_local_change "swift-pine" "app"

# rate-limits: "in-progress" — local commits
add_local_change "dry-fog" "gateway"

# infra-update: "in-review" — marker file
touch "$FLOW_HOME/workspaces/swift-pine/app/.flow-review"

# billing-v2: "closed" — marker file
touch "$FLOW_HOME/workspaces/calm-ridge/billing/.flow-closed"

# --- Create status specs ---
# The default spec (written by EnsureDirs on first flow command) uses gh + jq.
# For the demo, we keep the default for the edit-status tape (so it shows the
# real commands), then the status tape swaps in a local-only spec before running.

# Write a local-only spec that the status tape will swap in (no gh needed).
# Checks are evaluated in order — first match wins per repo.
cat > "$FLOW_HOME/status-local.yaml" <<YAML
apiVersion: flow/v1
kind: Status
spec:
statuses:
- name: closed
description: All PRs merged or closed
check: 'false'
check: test -f "\$FLOW_REPO_PATH/.flow-closed"
- name: in-review
description: Non-draft PR open
check: 'false'
check: test -f "\$FLOW_REPO_PATH/.flow-review"
- name: in-progress
description: Local diffs or draft PR
check: git -C "\$FLOW_REPO_PATH" diff --name-only "origin/\$FLOW_REPO_BRANCH" 2>/dev/null | grep -q .
Expand Down
Binary file modified demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading