# gitflow — Build & Run Guide ## Prerequisites | Requirement | Minimum | Check with | |---|---|---| | Go toolchain | 1.24 | `go version` | | Git | any recent | `git --version` | | `make` (optional) | — | `make --version` | | `golangci-lint` (optional) | any recent | `golangci-lint --version` | Linux, macOS, and Windows (WSL / MSYS2) are supported. The binary compiles for all three platforms (ARM64 on macOS verified). ## Quick start ```bash # Clone git clone https://gitea.oblak.solutions/dimitar/gitFlow.git cd gitFlow # Build (either method) make build # produces ./gitflow # or go build -o gitflow ./cmd/gitflow # Run ./gitflow version # → "gitflow dev" ./gitflow scan # scans $PWD, asks for directory if stdin is a tty ./gitflow scan -d ~/projects ``` ## Make targets ```makefile make build # compile the binary, injects VERSION via ldflags make test # run the full test suite (go test ./...) make fmt # format all Go sources (gofmt) make vet # run go vet over all packages make lint # run golangci-lint (needs it on PATH) make install # install into $GOPATH/bin (or $GOBIN) make clean # remove the binary and coverage output ``` **Stamped version** (optional): ```bash VERSION=v2.0.1 make build ./gitflow version # → "gitflow v2.0.1" ``` ## Commands | Command | Purpose | |---|---| | `scan` | One-shot scan of repos under `--dir`, render and exit | | `watch` | Rescan every `--interval`, detect changes, notify, fire webhooks | | `tui` | Interactive terminal UI (bubbletea) with navigation, detail pane, AI panel | | `config` | Print the resolved configuration (flags + env + file merged) | | `completion` | Emit shell completions for bash, zsh, fish, or PowerShell | | `version` | Print version and exit | Every command accepts the same flag set. Use `gitflow --help` for the full list. ### `scan` — single pass ```bash gitflow scan # prompt for dir, table output gitflow scan -d ~/projects # explicit dir gitflow scan -d ~/projects -f json # JSON to stdout, no human-facing sections gitflow scan -d ~ --exclude node_modules --exclude vendor gitflow scan -d ~/projects --max-depth 2 --workers 16 ``` ### `watch` — periodic scan --- ```bash gitflow watch -d ~/projects -i 30s # scan every 30 seconds gitflow watch -d ~/projects -i 5m --notify # also fire desktop notifications gitflow watch -d ~/projects -i 1m --theme=light --color=always ``` Webhooks fire automatically when a `webhooks:` section exists in your config file (no flag needed — they are config-only, like custom rules). ### `tui` — interactive terminal UI ```bash gitflow tui -d ~/projects # one-shot scan, browse with j/k gitflow tui -d ~/projects -i 30s # periodic scan, countdown in bar gitflow tui -d ~/projects --ai --ai-provider ollama ``` **TUI keybindings:** ``` ↑/↓ or j/k navigate repository list g / Home jump to top G / End jump to bottom Enter / Space toggle detail pane for selected repo r trigger immediate rescan a toggle AI suggestion panel (requires --ai) ? toggle help overlay q / Ctrl-C quit ``` ### `config` — show effective configuration ```bash gitflow config # defaults gitflow config -d /tmp -f compact # with flag overrides GITFLOW_DIR=/tmp gitflow config # with env overrides ``` ### `completion` — shell integration ```bash # bash eval "$(gitflow completion bash)" # zsh gitflow completion zsh > ~/.zsh/completion/_gitflow # fish gitflow completion fish > ~/.config/fish/completions/gitflow.fish # powershell gitflow completion powershell > gitflow.ps1 ``` ## Configuration Settings resolve with this precedence (highest first): 1. **CLI flags** — `--dir`, `--format`, etc. 2. **Environment variables** — `GITFLOW_` prefix, dots replaced by underscores: `GITFLOW_DIR`, `GITFLOW_FORMAT`, `GITFLOW_AI_PROVIDER`, … 3. **Config file** — `~/.gitflow.yaml` (or `./.gitflow.yaml`); override the path with `GITFLOW_CONFIG=/some/path.yaml` 4. **Built-in defaults** — `.` directory, `table` format, `auto` color, `dark` theme, 8 workers, AI disabled, etc. ### Complete config file reference ```yaml # ~/.gitflow.yaml dir: ~/projects interval: 5m format: table # table | json | compact color: auto # auto | always | never theme: dark # dark | light notify: true # desktop notifications (linux notify-send, macOS osascript) max_depth: 3 # 0 = unlimited workers: 8 exclude: # glob patterns matched against base name and full path - node_modules - vendor - ".cache" # AI agent (requires --ai flag or enabled: true) ai: enabled: false provider: openai # openai | ollama | anthropic model: gpt-4o # empty → provider default (ollama: llama3.2, anthropic: claude-3-5-haiku-latest) api_key_env: OPENAI_API_KEY base_url: "" # override provider endpoint; empty → vendor default execute: false # run confirmed AI commands (experimental, allowlist-guarded) # Custom threshold rules rules: - name: stale-branch field: behind # ahead | behind | stash | changes op: ">=" # == | != | < | <= | > | >= value: 10 label: stale - name: dirty-workspace field: changes op: ">=" value: 1 label: dirty # Webhooks (config-file-only, no CLI flags) webhooks: - name: team-slack type: slack # slack | discord | generic url: https://hooks.slack.com/services/T00/B00/TOKEN on_change_only: true # skip when nothing changed min_priority: 0 # 0 = fire on any change rate_limit: 5m # minimum interval between fires timeout: 10s # HTTP timeout per attempt retry: max_attempts: 3 # max 5 backoff: 2s # exponential backoff start - name: ops-discord type: discord url: https://discord.com/api/webhooks/... send_all: false # when true, include every repo, not just changed - name: internal-dashboard type: generic url: https://dashboard.internal/api/gitflow headers: Authorization: Bearer ${DASHBOARD_TOKEN} X-Source: gitflow ``` ### Environment variable mapping | Config key | Env var | |---|---| | `dir` | `GITFLOW_DIR` | | `interval` | `GITFLOW_INTERVAL` | | `format` | `GITFLOW_FORMAT` | | `color` | `GITFLOW_COLOR` | | `theme` | `GITFLOW_THEME` | | `notify` | `GITFLOW_NOTIFY` | | `max_depth` | `GITFLOW_MAX_DEPTH` | | `workers` | `GITFLOW_WORKERS` | | `exclude` | `GITFLOW_EXCLUDE` (comma-separated) | | `ai.enabled` | `GITFLOW_AI_ENABLED` | | `ai.provider` | `GITFLOW_AI_PROVIDER` | | `ai.model` | `GITFLOW_AI_MODEL` | | `ai.api_key_env` | `GITFLOW_AI_API_KEY_ENV` | | `ai.base_url` | `GITFLOW_AI_BASE_URL` | | `ai.execute` | `GITFLOW_AI_EXECUTE` | ## Output formats ### Table (default) ``` REPOSITORY BRANCH STATUS AHEAD/BEHIND CHANGES STASH ~/projects/api main clean - - - ~/projects/web feat/x modified 3/0 2M 1U - ~/projects/lib main behind 0/5 - 2 5 repos | 2 clean | 3 need attention | 0 errors ``` Colorised per status class (`--color=auto` respected, `NO_COLOR` honoured). Path prefix `$HOME` collapsed to `~`. ### JSON ```json { "scanned_at": "2026-08-02T10:00:00+02:00", "parent_dir": "/home/user/projects", "repos": [ { "path": "/home/user/projects/api", "name": "api", "branch": "main", "status": "clean" } ], "summary": { "total": 5, "clean": 2, "attention": 3, "errored": 0, "staged": 0, "modified": 2, "untracked": 1 } } ``` Status fields marshal as string labels (`"clean"`, `"modified"`, …) and unmarshal back from both strings and integers. ### Compact ``` ✓ ~/projects/api (main) ✗ ~/projects/web (feat/x) +3/-0 2 change(s) ↓ ~/projects/lib (main) +0/-5 ``` Status symbols: `✓ ✗ ↑ ↓ ⇄ ◉ ▢ !`. ## AI agent Enable with `--ai` (or `ai.enabled: true` in config): ```bash # OpenAI (requires OPENAI_API_KEY exported or ai.api_key_env set) gitflow scan -d ~/projects --ai # Local Ollama gitflow scan -d ~/projects --ai --ai-provider ollama --ai-model llama3.2 # Anthropic gitflow scan -d ~/projects --ai --ai-provider anthropic --ai-model claude-3-5-haiku-latest ``` Suggestions render below the scan table, colour-coded by priority: ``` AI SUGGESTIONS REPOSITORY ACTION PRIORITY MESSAGE COMMAND ~/projects/web commit high commit the new file git add -A && git commit -m wip ~/projects/lib pull medium pull 5 commits from origin git pull ``` In JSON mode AI is skipped (machine-readable streams stay clean). In watch mode AI is queried only on the first frame and when something changed. ### `--ai-execute` (experimental) Runs suggested commands after **explicit per-command y/N confirmation**, only for actions on an allowlist (`commit`, `push`, `pull`, `stash`, `checkout`). LLM output can never run arbitrary shell commands. ## Webhooks Webhooks fire in watch mode when `webhooks:` is present in the config file. They run in a background goroutine and never block the scan interval. Each webhook has independent rate limiting and retry with exponential backoff. Transient errors (5xx, timeouts) are retried; 4xx client errors fail immediately. **Slack Block Kit payload:** - Header: "gitflow: scan results" - Section: summary line with repo counts - Divider + changed-repo list (when changes exist) - Context footer: timestamp + "gitflow" **Discord embed payload:** - Sidebar colour: green (all clean), yellow (attention), red (errors) - Title: "gitflow scan" - Markdown body with summary + changed repos - Footer and timestamp **Generic payload:** - Raw JSON POST of the `webhook.Payload` struct (`timestamp`, `parent_dir`, `summary`, `changed`, `all`) to any URL with custom headers. ## Test suite ```bash make test # all packages, no race detection go test -race ./... # with data-race detector (13 packages) go test -count=1 -race ./internal/ai ./internal/webhook # specific packages ``` Coverage (latest run): | Package | Coverage | |---|---| | `internal/ai` | 84.9% | | `internal/app` | 76.9% | | `internal/config` | 90.9% | | `internal/git` | 79.6% | | `internal/httpclient` | 89.1% | | `internal/presenter` | 86.6% | | `internal/rules` | 83.3% | | `internal/scanner` | 88.2% | | `internal/scheduler` | 88.9% | | `internal/webhook` | 91.7% | | `internal/tui` | 89.4% | | `pkg/status` | 91.1% | ## Project layout ``` gitflow/ ├── cmd/gitflow/ CLI commands (cobra) │ ├── main.go entry point │ ├── root.go root command + version + completion │ ├── scan.go gitflow scan │ ├── watch.go gitflow watch │ ├── tui.go gitflow tui │ └── prompt.go TTY helpers (dir prompt, y/N confirmation) ├── internal/ │ ├── ai/ AI providers (OpenAI, Ollama, Anthropic) + prompt │ ├── app/ orchestration: discovery → scan → result │ ├── config/ flags, env, config-file resolution (viper) │ ├── git/ porcelain v2 git wrapper (executor pattern) │ ├── httpclient/ shared JSON HTTP client (timeout, bounded reads) │ ├── notify/ desktop notifications (notify-send / osascript) │ ├── presenter/ table / json / compact output + colors + themes │ ├── rules/ user-defined threshold rules │ ├── scanner/ repository discovery + concurrent status scanning │ ├── scheduler/ interval loop with graceful shutdown │ ├── tui/ interactive terminal UI (bubbletea + lipgloss) │ ├── version/ ldflags-injectable version │ └── webhook/ Slack, Discord, Generic webhook senders + dispatcher ├── pkg/status/ shared domain model (RepoInfo, RepoStatus, ScanResult) ├── go.mod / go.sum ├── Makefile ├── .golangci.yml ├── .github/workflows/ci.yml ├── readme.md user-facing README ├── implementation.md original development plan + progress ├── tui.md TUI & webhooks plan + milestone status └── buildAndRun.md this file ``` ## CI GitHub Actions workflow (`.github/workflows/ci.yml`): ``` jobs: test (matrix: go 1.24, 1.26) - go build ./... - go vet ./... - go test -race ./... lint - golangci-lint ``` No remote pushes were made during development — branches were committed and merged locally with `--no-ff`. ## Troubleshooting **"not a git repository" when scanning a directory that IS a repo** The repo's `.git` directory may be missing or the path might be a bare `.git` file pointing at a non-existent gitdir. Check `git status` manually in that directory. **"no repositories found"** The directory contains no `.git` entries. If you expected repos deeper in the tree, make sure `--max-depth` isn't set too low and no `--exclude` pattern shadows the subtree. **"ai: OPENAI_API_KEY is not set"** Export the key (or the env var name in `ai.api_key_env`) before running: ```bash export OPENAI_API_KEY=sk-... gitflow scan --ai ``` **TUI doesn't launch / exits immediately** The TUI requires a terminal that supports the alternate screen buffer. If you are piping or redirecting output, use `scan` or `watch` instead. **Webhook not firing** 1. Check `gitflow config` shows the `webhooks:` section. 2. Webhooks only fire in `watch` mode, not in `scan`. 3. If `on_change_only: true`, the webhook skips when nothing changed between frames. 4. If `rate_limit` is set, the webhook won't fire until the cooldown elapses. **Shell completion "command not found" after eval** Make sure `gitflow` is on your PATH (`go install` into `$GOBIN`): ```bash go install ./cmd/gitflow # Or sudo cp gitflow /usr/local/bin/ ``` ## Cross-compilation ```bash GOOS=linux GOARCH=amd64 go build -o gitflow-linux ./cmd/gitflow GOOS=darwin GOARCH=arm64 go build -o gitflow-darwin ./cmd/gitflow GOOS=windows GOARCH=amd64 go build -o gitflow.exe ./cmd/gitflow ```